From d1b166e350a28858f99135269994e4136fb0f932 Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Tue, 9 Jun 2026 19:36:23 +0200 Subject: [PATCH 1/5] feat(API): improve PATCH /projects/{project_id}/screenshots/{id} documentation --- paths/screenshots/update.yaml | 217 +++++++++++++++++++++++++--------- 1 file changed, 163 insertions(+), 54 deletions(-) diff --git a/paths/screenshots/update.yaml b/paths/screenshots/update.yaml index df4f3e29..f21184af 100644 --- a/paths/screenshots/update.yaml +++ b/paths/screenshots/update.yaml @@ -1,20 +1,89 @@ --- summary: Update a screenshot -description: Update an existing screenshot. -operationId: screenshot/update +description: | + Updates the name or description of an existing screenshot within a project. + + Use this operation to rename a screenshot or revise its description after upload. The + screenshot file itself cannot be replaced via this endpoint; to change the image, delete + the screenshot and create a new one. + + **Authorization:** Requires the `write` OAuth scope. The caller must have manage permission + on the screenshot resource (`grant_manage?`) and the project must not be protected. + Specifically, `ScreenshotPolicy#update?` (aliased from `create?`) requires + `permissions.grant_manage?(record) && !project.protected?`. Requests from users whose + token lacks the `write` scope, who lack manage permission, or who target a protected + project receive a 403 response. + + **Feature gate:** This endpoint is only available on plans that include the Screenshots + feature (`attachable_screenshots`). Accounts without this feature receive a 403 response + with a localized plan-upgrade message. + + On success, a `screenshots:update` event is dispatched to configured webhooks. + + **Error codes:** When a request cannot be completed, the response body includes a `message` + string and a `documentation_url` string. The table below lists the stable error codes + returned in the `message` field for each error condition. Error codes follow + `UPPER_SNAKE_CASE` format. + + | HTTP status | Error code | Condition | + |-------------|------------|-----------| + | 400 | `BAD_REQUEST` | Malformed request body (unparseable JSON), missing required parameter, or invalid branch reference. | + | 401 | `UNAUTHORIZED` | Missing or invalid authentication credentials, or invalid OTP (one-time password) code. | + | 403 | `FORBIDDEN` | Token lacks the `write` scope; caller lacks manage permission on the screenshot; project is protected; or account plan does not include the Screenshots feature. | + | 404 | `NOT_FOUND` | The project or screenshot does not exist, or is not accessible to the caller. | + | 422 | `UNPROCESSABLE_ENTITY` | Screenshot attributes failed model validation (for example, a blank or duplicate name). The `errors` array in the response body contains per-field details. | + | 429 | `RATE_LIMIT_EXCEEDED` | The caller has exceeded their per-minute request quota or concurrent-request limit. | +operationId: screenshots/update tags: -- Screenshots + - Screenshots parameters: -- "$ref": "../../parameters.yaml#/X-PhraseApp-OTP" -- "$ref": "../../parameters.yaml#/project_id" -- "$ref": "../../parameters.yaml#/id" + - "$ref": "../../parameters.yaml#/X-PhraseApp-OTP" + required: false + - "$ref": "../../parameters.yaml#/project_id" + required: true + - "$ref": "../../parameters.yaml#/id" + required: true + - name: branch + in: query + description: Specifies the branch to use. When omitted, the default branch is used. + required: false + schema: + type: string + example: my-feature-branch +requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: New name for the screenshot. + example: main_nav_v2 + description: + type: string + description: >- + Descriptive text for the screenshot, used to provide context for + translators. + example: Shows the main navigation bar after the v2 redesign + multipart/form-data: + schema: + type: object + properties: + name: + type: string + description: New name for the screenshot. + example: main_nav_v2 + description: + type: string + description: >- + Descriptive text for the screenshot, used to provide context for + translators. + example: Shows the main navigation bar after the v2 redesign responses: '200': description: OK - content: - application/json: - schema: - "$ref": "../../schemas/screenshot.yaml#/screenshot" headers: X-Rate-Limit-Limit: "$ref": "../../headers.yaml#/X-Rate-Limit-Limit" @@ -22,59 +91,99 @@ responses: "$ref": "../../headers.yaml#/X-Rate-Limit-Remaining" X-Rate-Limit-Reset: "$ref": "../../headers.yaml#/X-Rate-Limit-Reset" + content: + application/json: + schema: + "$ref": "../../schemas/screenshot.yaml#/screenshot" + example: + id: b827204f17cefe7fa3b6a8ced17ead26 + name: main_nav_v2 + description: Shows the main navigation bar after the v2 redesign + screenshot_url: "https://uploads.phrase.com/screenshots/b827204f17cefe7fa3b6a8ced17ead26/screenshot-7411f4f0a5c11802.jpg" + created_at: "2015-01-28T09:52:53Z" + updated_at: "2025-03-14T11:20:00Z" + markers_count: 2 '400': "$ref": "../../responses.yaml#/400" - '404': - "$ref": "../../responses.yaml#/404" + description: >- + Returned when the request body cannot be parsed (for example, malformed JSON), a + required parameter is missing, or the specified branch reference is not + interactable. Fix the request body or query parameters and retry. '401': "$ref": "../../responses.yaml#/401" + description: >- + Returned when no valid authentication credentials are provided, or when the + X-PhraseApp-OTP header contains an invalid one-time password code. Provide a + valid access token (Basic auth or Bearer token) and, when two-factor + authentication is enabled on the account, a current OTP value. '403': "$ref": "../../responses.yaml#/403" - description: Forbidden. Returned when the access token lacks the `write` scope, when the requesting user is not allowed to update this screenshot, or when the account does not have the Attachable Screenshots feature. + description: >- + Returned when the access token lacks the `write` scope, the caller does not + have manage permission on the screenshot, the project is protected, or the + account plan does not include the Screenshots feature. Ensure the token has + the `write` scope and the authenticated user has manage-level access to + the project. + '404': + "$ref": "../../responses.yaml#/404" + description: >- + Returned when the project or screenshot identified by `project_id` or `id` + does not exist, has been deleted, or is not accessible to the authenticated + user. Verify that both identifiers are correct and the user has access to + the project. '422': "$ref": "../../responses.yaml#/422" + description: >- + Returned when screenshot attributes fail model validation, for example when + the provided name is blank or conflicts with an existing screenshot. The + response body includes an `errors` array with per-field details. Correct the + field values indicated in `errors` and resubmit. '429': "$ref": "../../responses.yaml#/429" + description: >- + Returned when the caller exceeds their per-minute request quota or maximum + concurrent-request limit. Wait for the interval indicated by the + `X-Rate-Limit-Reset` response header before retrying. x-code-samples: -- lang: Curl - source: |- - curl "https://api.phrase.com/v2/projects/:project_id/screenshots/:id" \ - -u USERNAME_OR_ACCESS_TOKEN \ - -X PATCH \ - -F branch=my-feature-branch \ - -F name=A%20screenshot%20name \ - -F description=A%20screenshot%20description \ - -F filename=@/path/to/my/screenshot.png -- lang: CLI v2 - source: |- - phrase screenshots update \ - --project_id \ - --id \ - --data '{"branch":"my-feature-branch", "name": "A screenshot name", "description": "A screenshot description", "filename":"/path/to/my/screenshot.png"}' \ - --access_token -requestBody: - required: true - content: - application/json: - schema: - type: object - title: screenshot/update/parameters - properties: - branch: - description: specify the branch to use - type: string - example: my-feature-branch - name: - description: Name of the screenshot - type: string - example: A screenshot name - description: - description: Description of the screenshot - type: string - example: A screenshot description - filename: - description: Screenshot file - type: string - format: binary - example: "/path/to/my/screenshot.png" + - lang: Curl + source: |- + curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/screenshots/b827204f17cefe7fa3b6a8ced17ead26" \ + -u USERNAME:abcd1234abcd1234abcd1234abcd1234 \ + -X PATCH \ + -H "Content-Type: application/json" \ + -d '{"name":"main_nav_v2","description":"Shows the main navigation bar after the v2 redesign"}' + + # Example response (HTTP 200): + # { + # "id": "b827204f17cefe7fa3b6a8ced17ead26", + # "name": "main_nav_v2", + # "description": "Shows the main navigation bar after the v2 redesign", + # "screenshot_url": "https://uploads.phrase.com/screenshots/b827204f17cefe7fa3b6a8ced17ead26/screenshot-7411f4f0a5c11802.jpg", + # "created_at": "2015-01-28T09:52:53Z", + # "updated_at": "2025-03-14T11:20:00Z", + # "markers_count": 2 + # } + - lang: CLI v2 + source: |- + phrase screenshots update \ + --project_id abcd1234abcd1234abcd1234abcd1234 \ + --id b827204f17cefe7fa3b6a8ced17ead26 \ + --data '{"name":"main_nav_v2","description":"Shows the main navigation bar after the v2 redesign"}' \ + --access_token abcd1234abcd1234abcd1234abcd1234 + + # Example response (HTTP 200): + # { + # "id": "b827204f17cefe7fa3b6a8ced17ead26", + # "name": "main_nav_v2", + # "description": "Shows the main navigation bar after the v2 redesign", + # "screenshot_url": "https://uploads.phrase.com/screenshots/b827204f17cefe7fa3b6a8ced17ead26/screenshot-7411f4f0a5c11802.jpg", + # "created_at": "2015-01-28T09:52:53Z", + # "updated_at": "2025-03-14T11:20:00Z", + # "markers_count": 2 + # } x-cli-version: '2.5' +security: + - Basic: [] + - Token: [] + - OAuthAccessToken: + - write From ea6e59937809b511b10cdea84a954548dec22e92 Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Wed, 10 Jun 2026 13:33:21 +0200 Subject: [PATCH 2/5] feat(API): improve patch /projects/{project_id}/screenshots/{id} documentation --- paths/screenshots/update.yaml | 192 ++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 92 deletions(-) diff --git a/paths/screenshots/update.yaml b/paths/screenshots/update.yaml index f21184af..e574345c 100644 --- a/paths/screenshots/update.yaml +++ b/paths/screenshots/update.yaml @@ -1,38 +1,40 @@ --- summary: Update a screenshot description: | - Updates the name or description of an existing screenshot within a project. + Updates the name or description of an existing screenshot in a Phrase Strings project. - Use this operation to rename a screenshot or revise its description after upload. The - screenshot file itself cannot be replaced via this endpoint; to change the image, delete - the screenshot and create a new one. + Use this operation when you need to correct a screenshot's display name or clarify its description + for translators. Screenshots in Phrase Strings are images attached to translation keys to provide + visual context: they help translators understand where a string appears in the UI. Each screenshot + can have zero or more markers (`markers_count`) linking it to specific translation keys. - **Authorization:** Requires the `write` OAuth scope. The caller must have manage permission - on the screenshot resource (`grant_manage?`) and the project must not be protected. - Specifically, `ScreenshotPolicy#update?` (aliased from `create?`) requires - `permissions.grant_manage?(record) && !project.protected?`. Requests from users whose - token lacks the `write` scope, who lack manage permission, or who target a protected - project receive a 403 response. - - **Feature gate:** This endpoint is only available on plans that include the Screenshots - feature (`attachable_screenshots`). Accounts without this feature receive a 403 response - with a localized plan-upgrade message. + **Important constraints and pitfalls:** + - The `name` must be unique within the project (case-insensitive). Submitting a name that + already exists on another screenshot in the same project returns a 422 error. + - This endpoint does **not** accept a file upload. Replacing the image file (`filename`) is not + supported via the update operation; to change the image, delete the screenshot and create a + new one. + - All body parameters are optional. Send only the fields you want to change; omitted fields are + left unchanged. + - The Attachable Screenshots feature must be enabled on the account. Requests from accounts + without this feature receive a 403 response regardless of user permissions. + - Only users with Manage permissions on the project may update screenshots. Users with only Read + access receive a 403 response. On success, a `screenshots:update` event is dispatched to configured webhooks. - **Error codes:** When a request cannot be completed, the response body includes a `message` - string and a `documentation_url` string. The table below lists the stable error codes - returned in the `message` field for each error condition. Error codes follow - `UPPER_SNAKE_CASE` format. + **Error codes:** Phrase Strings does not return stable machine-readable error code strings beyond + the HTTP status code. Use the HTTP status to branch error handling; read the `message` field in + the response body for a human-readable explanation. - | HTTP status | Error code | Condition | - |-------------|------------|-----------| - | 400 | `BAD_REQUEST` | Malformed request body (unparseable JSON), missing required parameter, or invalid branch reference. | - | 401 | `UNAUTHORIZED` | Missing or invalid authentication credentials, or invalid OTP (one-time password) code. | - | 403 | `FORBIDDEN` | Token lacks the `write` scope; caller lacks manage permission on the screenshot; project is protected; or account plan does not include the Screenshots feature. | - | 404 | `NOT_FOUND` | The project or screenshot does not exist, or is not accessible to the caller. | - | 422 | `UNPROCESSABLE_ENTITY` | Screenshot attributes failed model validation (for example, a blank or duplicate name). The `errors` array in the response body contains per-field details. | - | 429 | `RATE_LIMIT_EXCEEDED` | The caller has exceeded their per-minute request quota or concurrent-request limit. | + | HTTP status | Condition | + |-------------|-----------| + | 400 | Malformed request body (unparseable JSON) or a parameter value is of an unexpected type. | + | 401 | Missing or invalid authentication credentials, or invalid OTP code. | + | 403 | Token lacks the `write` scope; caller lacks manage permission; or account plan does not include the Screenshots feature. | + | 404 | The project or screenshot does not exist or is not accessible to the caller. | + | 422 | Screenshot attributes failed model validation (for example, a blank or duplicate name). | + | 429 | The caller has exceeded their per-minute request quota or concurrent-request limit. | operationId: screenshots/update tags: - Screenshots @@ -45,7 +47,9 @@ parameters: required: true - name: branch in: query - description: Specifies the branch to use. When omitted, the default branch is used. + description: >- + Name of the branch to operate on. When supplied, the request is scoped to that + branch project rather than the main project. Omit to operate on the main project. required: false schema: type: string @@ -56,34 +60,41 @@ requestBody: application/json: schema: type: object + title: screenshot/update/parameters + description: All properties are optional. Include only the fields you want to update. properties: name: + description: >- + New display name for the screenshot. Must be unique within the project + (case-insensitive). If another screenshot in the project already uses this name, + the request fails with 422. type: string - description: New name for the screenshot. - example: main_nav_v2 + example: Onboarding step 1 — updated description: - type: string description: >- - Descriptive text for the screenshot, used to provide context for - translators. - example: Shows the main navigation bar after the v2 redesign + Updated description of what the screenshot shows. Helps translators understand the + UI context without opening the image. + type: string + example: First step of the onboarding flow after the redesign multipart/form-data: schema: type: object properties: name: type: string - description: New name for the screenshot. - example: main_nav_v2 + description: >- + New display name for the screenshot. Must be unique within the project + (case-insensitive). + example: Onboarding step 1 — updated description: type: string description: >- - Descriptive text for the screenshot, used to provide context for - translators. - example: Shows the main navigation bar after the v2 redesign + Updated description of what the screenshot shows. Helps translators understand the + UI context without opening the image. + example: First step of the onboarding flow after the redesign responses: '200': - description: OK + description: The screenshot was updated successfully. Returns the full screenshot object. headers: X-Rate-Limit-Limit: "$ref": "../../headers.yaml#/X-Rate-Limit-Limit" @@ -96,90 +107,87 @@ responses: schema: "$ref": "../../schemas/screenshot.yaml#/screenshot" example: - id: b827204f17cefe7fa3b6a8ced17ead26 - name: main_nav_v2 - description: Shows the main navigation bar after the v2 redesign - screenshot_url: "https://uploads.phrase.com/screenshots/b827204f17cefe7fa3b6a8ced17ead26/screenshot-7411f4f0a5c11802.jpg" - created_at: "2015-01-28T09:52:53Z" - updated_at: "2025-03-14T11:20:00Z" - markers_count: 2 + id: d2e056aa9e70b01121f41693e344f5ee + name: Onboarding step 1 — updated + description: First step of the onboarding flow after the redesign + screenshot_url: https://assets.phrase.com/screenshots/d2e056aa9e70b01121f41693e344f5ee.png + created_at: '2024-03-15T10:22:31Z' + updated_at: '2024-06-10T09:15:44Z' + markers_count: 3 '400': "$ref": "../../responses.yaml#/400" description: >- - Returned when the request body cannot be parsed (for example, malformed JSON), a - required parameter is missing, or the specified branch reference is not - interactable. Fix the request body or query parameters and retry. + Bad request. Returned when the request body cannot be parsed (for example, malformed JSON) + or a parameter value is of an unexpected type. Fix the request payload and retry. '401': "$ref": "../../responses.yaml#/401" description: >- - Returned when no valid authentication credentials are provided, or when the - X-PhraseApp-OTP header contains an invalid one-time password code. Provide a - valid access token (Basic auth or Bearer token) and, when two-factor - authentication is enabled on the account, a current OTP value. + Unauthorized. The access token is missing, expired, or invalid. Provide a valid token in + the `Authorization` header or via the `access_token` query parameter. '403': "$ref": "../../responses.yaml#/403" description: >- - Returned when the access token lacks the `write` scope, the caller does not - have manage permission on the screenshot, the project is protected, or the - account plan does not include the Screenshots feature. Ensure the token has - the `write` scope and the authenticated user has manage-level access to - the project. + Forbidden. Returned in three cases: (1) the access token lacks the `write` scope; + (2) the authenticated user does not have Manage permissions on this project; or + (3) the account does not have the Attachable Screenshots feature enabled. Check your + token scopes, your project role, and your subscription plan. '404': "$ref": "../../responses.yaml#/404" description: >- - Returned when the project or screenshot identified by `project_id` or `id` - does not exist, has been deleted, or is not accessible to the authenticated - user. Verify that both identifiers are correct and the user has access to - the project. + Not found. No screenshot with the given `id` exists in the specified project, or the + `project_id` does not match a project accessible to the authenticated user. Verify both + identifiers and retry. '422': "$ref": "../../responses.yaml#/422" description: >- - Returned when screenshot attributes fail model validation, for example when - the provided name is blank or conflicts with an existing screenshot. The - response body includes an `errors` array with per-field details. Correct the - field values indicated in `errors` and resubmit. + Unprocessable entity. The screenshot could not be saved due to a validation error — most + commonly because another screenshot in the project already has the same name + (case-insensitive). Read the `errors` array in the response body for the specific field + and message, then adjust the request accordingly. '429': "$ref": "../../responses.yaml#/429" description: >- - Returned when the caller exceeds their per-minute request quota or maximum - concurrent-request limit. Wait for the interval indicated by the - `X-Rate-Limit-Reset` response header before retrying. + Too many requests. Your account has exceeded the API rate limit. Wait until the time + indicated in the `X-Rate-Limit-Reset` header before retrying. x-code-samples: - lang: Curl source: |- - curl "https://api.phrase.com/v2/projects/abcd1234abcd1234abcd1234abcd1234/screenshots/b827204f17cefe7fa3b6a8ced17ead26" \ - -u USERNAME:abcd1234abcd1234abcd1234abcd1234 \ + curl "https://api.phrase.com/v2/projects/:project_id/screenshots/:id" \ + -u USERNAME_OR_ACCESS_TOKEN \ -X PATCH \ -H "Content-Type: application/json" \ - -d '{"name":"main_nav_v2","description":"Shows the main navigation bar after the v2 redesign"}' + -d '{ + "name": "Onboarding step 1 — updated", + "description": "First step of the onboarding flow after the redesign" + }' - # Example response (HTTP 200): + # Expected response (200 OK): # { - # "id": "b827204f17cefe7fa3b6a8ced17ead26", - # "name": "main_nav_v2", - # "description": "Shows the main navigation bar after the v2 redesign", - # "screenshot_url": "https://uploads.phrase.com/screenshots/b827204f17cefe7fa3b6a8ced17ead26/screenshot-7411f4f0a5c11802.jpg", - # "created_at": "2015-01-28T09:52:53Z", - # "updated_at": "2025-03-14T11:20:00Z", - # "markers_count": 2 + # "id": "d2e056aa9e70b01121f41693e344f5ee", + # "name": "Onboarding step 1 — updated", + # "description": "First step of the onboarding flow after the redesign", + # "screenshot_url": "https://assets.phrase.com/screenshots/d2e056aa9e70b01121f41693e344f5ee.png", + # "created_at": "2024-03-15T10:22:31Z", + # "updated_at": "2024-06-10T09:15:44Z", + # "markers_count": 3 # } - lang: CLI v2 source: |- phrase screenshots update \ - --project_id abcd1234abcd1234abcd1234abcd1234 \ - --id b827204f17cefe7fa3b6a8ced17ead26 \ - --data '{"name":"main_nav_v2","description":"Shows the main navigation bar after the v2 redesign"}' \ - --access_token abcd1234abcd1234abcd1234abcd1234 + --project_id :project_id \ + --id :id \ + --data '{"name":"Onboarding step 1 — updated","description":"First step of the onboarding flow after the redesign"}' \ + --access_token - # Example response (HTTP 200): + # Expected response (200 OK): # { - # "id": "b827204f17cefe7fa3b6a8ced17ead26", - # "name": "main_nav_v2", - # "description": "Shows the main navigation bar after the v2 redesign", - # "screenshot_url": "https://uploads.phrase.com/screenshots/b827204f17cefe7fa3b6a8ced17ead26/screenshot-7411f4f0a5c11802.jpg", - # "created_at": "2015-01-28T09:52:53Z", - # "updated_at": "2025-03-14T11:20:00Z", - # "markers_count": 2 + # "id": "d2e056aa9e70b01121f41693e344f5ee", + # "name": "Onboarding step 1 — updated", + # "description": "First step of the onboarding flow after the redesign", + # "screenshot_url": "https://assets.phrase.com/screenshots/d2e056aa9e70b01121f41693e344f5ee.png", + # "created_at": "2024-03-15T10:22:31Z", + # "updated_at": "2024-06-10T09:15:44Z", + # "markers_count": 3 # } x-cli-version: '2.5' security: From 6c942582aa78411ea8b373f6fd37d71b3fb81ca5 Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Wed, 10 Jun 2026 13:57:25 +0200 Subject: [PATCH 3/5] fix: keep original operationId screenshot/update Renaming an operationId changes generated client method and model names in every SDK, which is a breaking change. The repo convention is singular resource names for single-resource operations (plural only for /list); the rename also broke client generation in CI. Co-Authored-By: Claude Fable 5 --- paths/screenshots/update.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paths/screenshots/update.yaml b/paths/screenshots/update.yaml index e574345c..f8f78d8a 100644 --- a/paths/screenshots/update.yaml +++ b/paths/screenshots/update.yaml @@ -35,7 +35,7 @@ description: | | 404 | The project or screenshot does not exist or is not accessible to the caller. | | 422 | Screenshot attributes failed model validation (for example, a blank or duplicate name). | | 429 | The caller has exceeded their per-minute request quota or concurrent-request limit. | -operationId: screenshots/update +operationId: screenshot/update tags: - Screenshots parameters: From 59a5991f0fc5bce9689f5959a663897505544638 Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Wed, 10 Jun 2026 14:05:58 +0200 Subject: [PATCH 4/5] fix: restore branch as a body parameter and drop the untitled multipart schema The untitled multipart/form-data inline schema broke client generation: the generator imports the operationId-derived model name while the titled application/json schema generates under its own name, leaving a missing symbol in the Java client. The update endpoint only meaningfully accepts JSON (screenshot_update_params permits name and description only), so the multipart block goes. branch moves back into the request body to match main and every sibling write endpoint; Rails merges query and body params, so the body shape is the compatible, convention-consistent one. filename stays removed: the controller does not permit it on update. Co-Authored-By: Claude Fable 5 --- paths/screenshots/update.yaml | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/paths/screenshots/update.yaml b/paths/screenshots/update.yaml index f8f78d8a..f101d5fb 100644 --- a/paths/screenshots/update.yaml +++ b/paths/screenshots/update.yaml @@ -40,20 +40,8 @@ tags: - Screenshots parameters: - "$ref": "../../parameters.yaml#/X-PhraseApp-OTP" - required: false - "$ref": "../../parameters.yaml#/project_id" - required: true - "$ref": "../../parameters.yaml#/id" - required: true - - name: branch - in: query - description: >- - Name of the branch to operate on. When supplied, the request is scoped to that - branch project rather than the main project. Omit to operate on the main project. - required: false - schema: - type: string - example: my-feature-branch requestBody: required: true content: @@ -63,6 +51,12 @@ requestBody: title: screenshot/update/parameters description: All properties are optional. Include only the fields you want to update. properties: + branch: + description: >- + Name of the branch to operate on. When supplied, the request is scoped to that + branch project rather than the main project. Omit to operate on the main project. + type: string + example: my-feature-branch name: description: >- New display name for the screenshot. Must be unique within the project @@ -76,22 +70,6 @@ requestBody: UI context without opening the image. type: string example: First step of the onboarding flow after the redesign - multipart/form-data: - schema: - type: object - properties: - name: - type: string - description: >- - New display name for the screenshot. Must be unique within the project - (case-insensitive). - example: Onboarding step 1 — updated - description: - type: string - description: >- - Updated description of what the screenshot shows. Helps translators understand the - UI context without opening the image. - example: First step of the onboarding flow after the redesign responses: '200': description: The screenshot was updated successfully. Returns the full screenshot object. From ba0d125ac35ded6201dce8a7628aacb342a8715c Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Wed, 10 Jun 2026 14:08:58 +0200 Subject: [PATCH 5/5] chore: regenerate doc/compiled.json The compare-output CI job diffs the committed bundle against a fresh swagger-cli compile, so spec changes must ship the regenerated bundle. Co-Authored-By: Claude Fable 5 --- doc/compiled.json | 124 +++++++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index bf43680f..3f6cad50 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -21315,7 +21315,7 @@ }, "patch": { "summary": "Update a screenshot", - "description": "Update an existing screenshot.", + "description": "Updates the name or description of an existing screenshot in a Phrase Strings project.\n\nUse this operation when you need to correct a screenshot's display name or clarify its description\nfor translators. Screenshots in Phrase Strings are images attached to translation keys to provide\nvisual context: they help translators understand where a string appears in the UI. Each screenshot\ncan have zero or more markers (`markers_count`) linking it to specific translation keys.\n\n**Important constraints and pitfalls:**\n- The `name` must be unique within the project (case-insensitive). Submitting a name that\n already exists on another screenshot in the same project returns a 422 error.\n- This endpoint does **not** accept a file upload. Replacing the image file (`filename`) is not\n supported via the update operation; to change the image, delete the screenshot and create a\n new one.\n- All body parameters are optional. Send only the fields you want to change; omitted fields are\n left unchanged.\n- The Attachable Screenshots feature must be enabled on the account. Requests from accounts\n without this feature receive a 403 response regardless of user permissions.\n- Only users with Manage permissions on the project may update screenshots. Users with only Read\n access receive a 403 response.\n\nOn success, a `screenshots:update` event is dispatched to configured webhooks.\n\n**Error codes:** Phrase Strings does not return stable machine-readable error code strings beyond\nthe HTTP status code. Use the HTTP status to branch error handling; read the `message` field in\nthe response body for a human-readable explanation.\n\n| HTTP status | Condition |\n|-------------|-----------|\n| 400 | Malformed request body (unparseable JSON) or a parameter value is of an unexpected type. |\n| 401 | Missing or invalid authentication credentials, or invalid OTP code. |\n| 403 | Token lacks the `write` scope; caller lacks manage permission; or account plan does not include the Screenshots feature. |\n| 404 | The project or screenshot does not exist or is not accessible to the caller. |\n| 422 | Screenshot attributes failed model validation (for example, a blank or duplicate name). |\n| 429 | The caller has exceeded their per-minute request quota or concurrent-request limit. |\n", "operationId": "screenshot/update", "tags": [ "Screenshots" @@ -21331,16 +21331,38 @@ "$ref": "#/components/parameters/id" } ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/screenshot" + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "title": "screenshot/update/parameters", + "description": "All properties are optional. Include only the fields you want to update.", + "properties": { + "branch": { + "description": "Name of the branch to operate on. When supplied, the request is scoped to that branch project rather than the main project. Omit to operate on the main project.", + "type": "string", + "example": "my-feature-branch" + }, + "name": { + "description": "New display name for the screenshot. Must be unique within the project (case-insensitive). If another screenshot in the project already uses this name, the request fails with 422.", + "type": "string", + "example": "Onboarding step 1 — updated" + }, + "description": { + "description": "Updated description of what the screenshot shows. Helps translators understand the UI context without opening the image.", + "type": "string", + "example": "First step of the onboarding flow after the redesign" + } } } - }, + } + } + }, + "responses": { + "200": { + "description": "The screenshot was updated successfully. Returns the full screenshot object.", "headers": { "X-Rate-Limit-Limit": { "$ref": "#/components/headers/X-Rate-Limit-Limit" @@ -21351,73 +21373,73 @@ "X-Rate-Limit-Reset": { "$ref": "#/components/headers/X-Rate-Limit-Reset" } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/screenshot" + }, + "example": { + "id": "d2e056aa9e70b01121f41693e344f5ee", + "name": "Onboarding step 1 — updated", + "description": "First step of the onboarding flow after the redesign", + "screenshot_url": "https://assets.phrase.com/screenshots/d2e056aa9e70b01121f41693e344f5ee.png", + "created_at": "2024-03-15T10:22:31Z", + "updated_at": "2024-06-10T09:15:44Z", + "markers_count": 3 + } + } } }, "400": { - "$ref": "#/components/responses/400" + "$ref": "#/components/responses/400", + "description": "Bad request. Returned when the request body cannot be parsed (for example, malformed JSON) or a parameter value is of an unexpected type. Fix the request payload and retry." }, "401": { - "$ref": "#/components/responses/401" + "$ref": "#/components/responses/401", + "description": "Unauthorized. The access token is missing, expired, or invalid. Provide a valid token in the `Authorization` header or via the `access_token` query parameter." }, "403": { "$ref": "#/components/responses/403", - "description": "Forbidden. Returned when the access token lacks the `write` scope, when the requesting user is not allowed to update this screenshot, or when the account does not have the Attachable Screenshots feature." + "description": "Forbidden. Returned in three cases: (1) the access token lacks the `write` scope; (2) the authenticated user does not have Manage permissions on this project; or (3) the account does not have the Attachable Screenshots feature enabled. Check your token scopes, your project role, and your subscription plan." }, "404": { - "$ref": "#/components/responses/404" + "$ref": "#/components/responses/404", + "description": "Not found. No screenshot with the given `id` exists in the specified project, or the `project_id` does not match a project accessible to the authenticated user. Verify both identifiers and retry." }, "422": { - "$ref": "#/components/responses/422" + "$ref": "#/components/responses/422", + "description": "Unprocessable entity. The screenshot could not be saved due to a validation error — most commonly because another screenshot in the project already has the same name (case-insensitive). Read the `errors` array in the response body for the specific field and message, then adjust the request accordingly." }, "429": { - "$ref": "#/components/responses/429" + "$ref": "#/components/responses/429", + "description": "Too many requests. Your account has exceeded the API rate limit. Wait until the time indicated in the `X-Rate-Limit-Reset` header before retrying." } }, "x-code-samples": [ { "lang": "Curl", - "source": "curl \"https://api.phrase.com/v2/projects/:project_id/screenshots/:id\" \\\n -u USERNAME_OR_ACCESS_TOKEN \\\n -X PATCH \\\n -F branch=my-feature-branch \\\n -F name=A%20screenshot%20name \\\n -F description=A%20screenshot%20description \\\n -F filename=@/path/to/my/screenshot.png" + "source": "curl \"https://api.phrase.com/v2/projects/:project_id/screenshots/:id\" \\\n -u USERNAME_OR_ACCESS_TOKEN \\\n -X PATCH \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"name\": \"Onboarding step 1 — updated\",\n \"description\": \"First step of the onboarding flow after the redesign\"\n }'\n\n# Expected response (200 OK):\n# {\n# \"id\": \"d2e056aa9e70b01121f41693e344f5ee\",\n# \"name\": \"Onboarding step 1 — updated\",\n# \"description\": \"First step of the onboarding flow after the redesign\",\n# \"screenshot_url\": \"https://assets.phrase.com/screenshots/d2e056aa9e70b01121f41693e344f5ee.png\",\n# \"created_at\": \"2024-03-15T10:22:31Z\",\n# \"updated_at\": \"2024-06-10T09:15:44Z\",\n# \"markers_count\": 3\n# }" }, { "lang": "CLI v2", - "source": "phrase screenshots update \\\n--project_id \\\n--id \\\n--data '{\"branch\":\"my-feature-branch\", \"name\": \"A screenshot name\", \"description\": \"A screenshot description\", \"filename\":\"/path/to/my/screenshot.png\"}' \\\n--access_token " + "source": "phrase screenshots update \\\n --project_id :project_id \\\n --id :id \\\n --data '{\"name\":\"Onboarding step 1 — updated\",\"description\":\"First step of the onboarding flow after the redesign\"}' \\\n --access_token \n\n# Expected response (200 OK):\n# {\n# \"id\": \"d2e056aa9e70b01121f41693e344f5ee\",\n# \"name\": \"Onboarding step 1 — updated\",\n# \"description\": \"First step of the onboarding flow after the redesign\",\n# \"screenshot_url\": \"https://assets.phrase.com/screenshots/d2e056aa9e70b01121f41693e344f5ee.png\",\n# \"created_at\": \"2024-03-15T10:22:31Z\",\n# \"updated_at\": \"2024-06-10T09:15:44Z\",\n# \"markers_count\": 3\n# }" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "title": "screenshot/update/parameters", - "properties": { - "branch": { - "description": "specify the branch to use", - "type": "string", - "example": "my-feature-branch" - }, - "name": { - "description": "Name of the screenshot", - "type": "string", - "example": "A screenshot name" - }, - "description": { - "description": "Description of the screenshot", - "type": "string", - "example": "A screenshot description" - }, - "filename": { - "description": "Screenshot file", - "type": "string", - "format": "binary", - "example": "/path/to/my/screenshot.png" - } - } - } - } + "x-cli-version": "2.5", + "security": [ + { + "Basic": [] + }, + { + "Token": [] + }, + { + "OAuthAccessToken": [ + "write" + ] } - }, - "x-cli-version": "2.5" + ] }, "delete": { "summary": "Delete a screenshot",