From 059cfa7523e2132e8bb5cf9df418938034cc37c3 Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Mon, 15 Jun 2026 14:08:36 +0200 Subject: [PATCH 1/7] feat(API): improve delete /projects/{project_id}/keys/{id}/key_links documentation --- doc/compiled.json | 297 +++++++++++++++++++++++++++-- paths/key_links/batch_destroy.yaml | 273 +++++++++++++++++++++++++- 2 files changed, 550 insertions(+), 20 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index afba5090..a177bdc4 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -30804,7 +30804,7 @@ "/projects/{project_id}/keys/{id}/key_links": { "delete": { "summary": "Batch unlink child keys from a parent key", - "description": "Unlinks multiple child keys from a given parent key in a single operation.", + "description": "Removes one or more child keys from a parent key's linked-key group, or dissolves the entire group by setting unlink_parent to true.\n\nUse this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content).\n\nThis operation requires write permission on the linked-key resource and is only available on main projects; calling it against a branch project returns 403. Specifying a child key that is not currently linked to the given parent returns 422 with error code KEY_IS_NOT_LINKED. Error codes follow UPPER_SNAKE_CASE format throughout this API.\n", "operationId": "key_links/batch_destroy", "tags": [ "Linked Keys" @@ -30821,7 +30821,7 @@ } ], "requestBody": { - "required": true, + "required": false, "content": { "application/json": { "schema": { @@ -30832,20 +30832,30 @@ "title": "key_links/batch_destroy/parameters", "properties": { "child_key_ids": { - "description": "The IDs of the child keys to unlink from the parent key.", + "description": "Codes of the child keys to unlink. Required when unlink_parent is false or omitted. Ignored when unlink_parent is true.", "type": "array", "example": [ - "child_key_id1", - "child_key_id2" + "feature.subtitle", + "nav.home" ], "items": { - "type": "string" + "type": "string", + "example": "feature.subtitle" } }, "unlink_parent": { - "description": "Whether to unlink the parent key as well and unmark it as linked-key.", + "description": "When true, dissolves the entire linked-key group by unlinking all children and removing the group. The child_key_ids field is ignored when this is set to true.", "type": "boolean", "default": false + }, + "strategy": { + "type": "string", + "description": "Controls what happens to child key translation content after unlinking. keep_content (default) copies the parent translation into each child; remove_content clears each child translation.", + "enum": [ + "keep_content", + "remove_content" + ], + "default": "keep_content" } } } @@ -30854,28 +30864,291 @@ }, "responses": { "200": { - "description": "OK" + "description": "Updated linked-key group reference after the unlink operation.", + "content": { + "application/json": { + "schema": { + "title": "linked_keys_reference", + "type": "object", + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the linked-key group was created." + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "When the linked-key group was last modified." + }, + "created_by": { + "type": "object", + "title": "linked_keys_reference/created_by", + "description": "User who created the linked-key group.", + "properties": { + "id": { + "type": "string", + "description": "User identifier (code)." + }, + "username": { + "type": "string" + }, + "name": { + "type": "string" + }, + "gravatar_uid": { + "type": "string" + } + } + }, + "updated_by": { + "type": "object", + "title": "linked_keys_reference/updated_by", + "description": "User who last modified the linked-key group.", + "properties": { + "id": { + "type": "string", + "description": "User identifier (code)." + }, + "username": { + "type": "string" + }, + "name": { + "type": "string" + }, + "gravatar_uid": { + "type": "string" + } + } + }, + "account": { + "type": "object", + "title": "linked_keys_reference/account", + "description": "Account the linked-key group belongs to.", + "properties": { + "id": { + "type": "string", + "description": "Account identifier (code)." + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "company": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "company_logo_url": { + "type": "string", + "format": "uri", + "description": "URL of the account company logo image." + } + } + }, + "parent": { + "type": "object", + "title": "linked_keys_reference/parent", + "description": "The parent key that owns this linked-key group.", + "properties": { + "id": { + "type": "string", + "description": "Key identifier (code)." + }, + "name": { + "type": "string" + }, + "plural": { + "type": "boolean", + "description": "Whether the key is pluralized." + }, + "use_ordinal_rules": { + "type": "boolean" + }, + "data_type": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "children": { + "type": "array", + "description": "Child keys remaining in the linked-key group after the operation. Empty when unlink_parent dissolves the group entirely.", + "items": { + "type": "object", + "title": "linked_keys_reference/child", + "properties": { + "id": { + "type": "string", + "description": "Key identifier (code)." + }, + "name": { + "type": "string" + }, + "plural": { + "type": "boolean", + "description": "Whether the key is pluralized." + }, + "use_ordinal_rules": { + "type": "boolean" + }, + "data_type": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "example": { + "created_at": "2024-03-15T10:30:00.000Z", + "updated_at": "2024-03-15T12:45:00.000Z", + "created_by": { + "id": "abcd1234efgh5678", + "username": "alice", + "name": "Alice Smith", + "gravatar_uid": "efgh5678abcd1234" + }, + "updated_by": { + "id": "ijkl9012mnop3456", + "username": "bob", + "name": "Bob Jones", + "gravatar_uid": "mnop3456ijkl9012" + }, + "account": { + "id": "qrst7890uvwx1234", + "name": "Acme Corp", + "slug": "acme-corp", + "company": "Acme Corporation", + "created_at": "2023-01-01T00:00:00.000Z", + "updated_at": "2024-03-15T12:45:00.000Z", + "company_logo_url": "https://assets.phrase.com/accounts/acme-corp/logo.png" + }, + "parent": { + "id": "main.title", + "name": "main.title", + "plural": false, + "use_ordinal_rules": false, + "data_type": "string", + "tags": [ + "ui", + "homepage" + ] + }, + "children": [ + { + "id": "feature.subtitle", + "name": "feature.subtitle", + "plural": false, + "use_ordinal_rules": false, + "data_type": "string", + "tags": [] + } + ] + } + } + } }, "400": { + "description": "Returned when a request parameter cannot be parsed or is structurally invalid. Correct the request body or query parameters and retry.", "$ref": "#/components/responses/400" }, "401": { + "description": "Returned when the access token is missing or invalid. Provide a valid token with the write scope and retry.", "$ref": "#/components/responses/401" }, "403": { - "$ref": "#/components/responses/403", - "description": "Forbidden. Returned when the access token lacks the `write` scope or when the requesting user is not allowed to unlink keys for this parent." + "description": "Returned when the caller lacks write permission on the linked-key resource, or when the target project is a branch rather than a main project. To resolve, verify that the access token carries the write scope and that the operation targets a main project.\n\nMachine-readable code: FORBIDDEN\n", + "$ref": "#/components/responses/403" }, "404": { + "description": "Returned when no key matching the given id exists in the project. Verify the key code and project identifier and retry.", "$ref": "#/components/responses/404" }, "422": { - "$ref": "#/components/responses/422" + "description": "Returned when validation fails. All error codes follow UPPER_SNAKE_CASE format.\n\nCommon codes:\n- KEY_IS_NOT_LINKED: a key in child_key_ids is not currently linked to the specified parent key. Verify the child key codes and the parent key before retrying.\n- CREATING_OR_UPDATING_TRANSLATION_ERROR: a translation update for an unlinked child key failed. Retry the request; if the error persists, verify that the child key's translations are not locked or in a state that prevents edits.\n", + "content": { + "application/json": { + "schema": { + "type": "object", + "title": "key_links/batch_destroy/error", + "properties": { + "message": { + "type": "string", + "description": "Human-readable error summary." + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "title": "key_links/batch_destroy/error_item", + "properties": { + "resource": { + "type": "string" + }, + "field": { + "type": "string" + }, + "message": { + "type": "string" + }, + "code": { + "type": "string", + "description": "Machine-readable UPPER_SNAKE_CASE error code identifying the failure reason.", + "enum": [ + "KEY_IS_NOT_LINKED", + "CREATING_OR_UPDATING_TRANSLATION_ERROR" + ] + } + } + } + } + } + }, + "example": { + "message": "Validation failed", + "errors": [ + { + "resource": "base", + "field": "", + "message": "Key feature.subtitle is not linked to main.title", + "code": "KEY_IS_NOT_LINKED" + } + ] + } + } + } }, "429": { + "description": "Returned when the rate limit is exceeded. Wait until the time indicated by the X-Rate-Limit-Reset header before retrying.", "$ref": "#/components/responses/429" } - } + }, + "x-code-samples": [ + { + "lang": "Curl", + "source": "curl \"https://api.phrase.com/v2/projects/:project_id/keys/:id/key_links\" \\\n -u USERNAME_OR_ACCESS_TOKEN \\\n -X DELETE \\\n -H \"Content-Type: application/json\" \\\n -d '{\"child_key_ids\": [\"feature.subtitle\", \"nav.home\"], \"strategy\": \"keep_content\"}'\n\nResponse (HTTP 200):\n{\n \"created_at\": \"2024-03-15T10:30:00.000Z\",\n \"updated_at\": \"2024-03-15T12:45:00.000Z\",\n \"created_by\": {\n \"id\": \"abcd1234efgh5678\",\n \"username\": \"alice\",\n \"name\": \"Alice Smith\",\n \"gravatar_uid\": \"efgh5678abcd1234\"\n },\n \"updated_by\": {\n \"id\": \"ijkl9012mnop3456\",\n \"username\": \"bob\",\n \"name\": \"Bob Jones\",\n \"gravatar_uid\": \"mnop3456ijkl9012\"\n },\n \"account\": {\n \"id\": \"qrst7890uvwx1234\",\n \"name\": \"Acme Corp\",\n \"slug\": \"acme-corp\",\n \"company\": \"Acme Corporation\",\n \"created_at\": \"2023-01-01T00:00:00.000Z\",\n \"updated_at\": \"2024-03-15T12:45:00.000Z\",\n \"company_logo_url\": \"https://assets.phrase.com/accounts/acme-corp/logo.png\"\n },\n \"parent\": {\n \"id\": \"main.title\",\n \"name\": \"main.title\",\n \"plural\": false,\n \"use_ordinal_rules\": false,\n \"data_type\": \"string\",\n \"tags\": [\"ui\", \"homepage\"]\n },\n \"children\": [\n {\n \"id\": \"feature.subtitle\",\n \"name\": \"feature.subtitle\",\n \"plural\": false,\n \"use_ordinal_rules\": false,\n \"data_type\": \"string\",\n \"tags\": []\n }\n ]\n}" + } + ] }, "get": { "summary": "List child keys of a parent key", diff --git a/paths/key_links/batch_destroy.yaml b/paths/key_links/batch_destroy.yaml index 758f677e..d3bcdb0c 100644 --- a/paths/key_links/batch_destroy.yaml +++ b/paths/key_links/batch_destroy.yaml @@ -1,5 +1,10 @@ summary: Batch unlink child keys from a parent key -description: Unlinks multiple child keys from a given parent key in a single operation. +description: | + Removes one or more child keys from a parent key's linked-key group, or dissolves the entire group by setting unlink_parent to true. + + Use this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content). + + This operation requires write permission on the linked-key resource and is only available on main projects; calling it against a branch project returns 403. Specifying a child key that is not currently linked to the given parent returns 422 with error code KEY_IS_NOT_LINKED. Error codes follow UPPER_SNAKE_CASE format throughout this API. operationId: key_links/batch_destroy tags: - Linked Keys @@ -8,7 +13,7 @@ parameters: - "$ref": "../../parameters.yaml#/project_id" - "$ref": "../../parameters.yaml#/key_id_as_id" requestBody: - required: true + required: false content: application/json: schema: @@ -18,28 +23,280 @@ requestBody: title: key_links/batch_destroy/parameters properties: child_key_ids: - description: The IDs of the child keys to unlink from the parent key. + description: Codes of the child keys to unlink. Required when unlink_parent is false or omitted. Ignored when unlink_parent is true. type: array - example: ["child_key_id1", "child_key_id2"] + example: ["feature.subtitle", "nav.home"] items: type: string + example: "feature.subtitle" unlink_parent: - description: Whether to unlink the parent key as well and unmark it as linked-key. + description: When true, dissolves the entire linked-key group by unlinking all children and removing the group. The child_key_ids field is ignored when this is set to true. type: boolean default: false + strategy: + type: string + description: Controls what happens to child key translation content after unlinking. keep_content (default) copies the parent translation into each child; remove_content clears each child translation. + enum: + - keep_content + - remove_content + default: keep_content responses: '200': - description: OK + description: Updated linked-key group reference after the unlink operation. + content: + application/json: + schema: + title: linked_keys_reference + type: object + properties: + created_at: + type: string + format: date-time + description: When the linked-key group was created. + updated_at: + type: string + format: date-time + description: When the linked-key group was last modified. + created_by: + type: object + title: linked_keys_reference/created_by + description: User who created the linked-key group. + properties: + id: + type: string + description: User identifier (code). + username: + type: string + name: + type: string + gravatar_uid: + type: string + updated_by: + type: object + title: linked_keys_reference/updated_by + description: User who last modified the linked-key group. + properties: + id: + type: string + description: User identifier (code). + username: + type: string + name: + type: string + gravatar_uid: + type: string + account: + type: object + title: linked_keys_reference/account + description: Account the linked-key group belongs to. + properties: + id: + type: string + description: Account identifier (code). + name: + type: string + slug: + type: string + company: + type: string + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + company_logo_url: + type: string + format: uri + description: URL of the account company logo image. + parent: + type: object + title: linked_keys_reference/parent + description: The parent key that owns this linked-key group. + properties: + id: + type: string + description: Key identifier (code). + name: + type: string + plural: + type: boolean + description: Whether the key is pluralized. + use_ordinal_rules: + type: boolean + data_type: + type: string + tags: + type: array + items: + type: string + children: + type: array + description: Child keys remaining in the linked-key group after the operation. Empty when unlink_parent dissolves the group entirely. + items: + type: object + title: linked_keys_reference/child + properties: + id: + type: string + description: Key identifier (code). + name: + type: string + plural: + type: boolean + description: Whether the key is pluralized. + use_ordinal_rules: + type: boolean + data_type: + type: string + tags: + type: array + items: + type: string + example: + created_at: "2024-03-15T10:30:00.000Z" + updated_at: "2024-03-15T12:45:00.000Z" + created_by: + id: "abcd1234efgh5678" + username: "alice" + name: "Alice Smith" + gravatar_uid: "efgh5678abcd1234" + updated_by: + id: "ijkl9012mnop3456" + username: "bob" + name: "Bob Jones" + gravatar_uid: "mnop3456ijkl9012" + account: + id: "qrst7890uvwx1234" + name: "Acme Corp" + slug: "acme-corp" + company: "Acme Corporation" + created_at: "2023-01-01T00:00:00.000Z" + updated_at: "2024-03-15T12:45:00.000Z" + company_logo_url: "https://assets.phrase.com/accounts/acme-corp/logo.png" + parent: + id: "main.title" + name: "main.title" + plural: false + use_ordinal_rules: false + data_type: "string" + tags: ["ui", "homepage"] + children: + - id: "feature.subtitle" + name: "feature.subtitle" + plural: false + use_ordinal_rules: false + data_type: "string" + tags: [] '400': + description: Returned when a request parameter cannot be parsed or is structurally invalid. Correct the request body or query parameters and retry. "$ref": "../../responses.yaml#/400" '401': + description: Returned when the access token is missing or invalid. Provide a valid token with the write scope and retry. "$ref": "../../responses.yaml#/401" '403': + description: | + Returned when the caller lacks write permission on the linked-key resource, or when the target project is a branch rather than a main project. To resolve, verify that the access token carries the write scope and that the operation targets a main project. + + Machine-readable code: FORBIDDEN "$ref": "../../responses.yaml#/403" - description: Forbidden. Returned when the access token lacks the `write` scope or when the requesting user is not allowed to unlink keys for this parent. '404': + description: Returned when no key matching the given id exists in the project. Verify the key code and project identifier and retry. "$ref": "../../responses.yaml#/404" '422': - "$ref": "../../responses.yaml#/422" + description: | + Returned when validation fails. All error codes follow UPPER_SNAKE_CASE format. + + Common codes: + - KEY_IS_NOT_LINKED: a key in child_key_ids is not currently linked to the specified parent key. Verify the child key codes and the parent key before retrying. + - CREATING_OR_UPDATING_TRANSLATION_ERROR: a translation update for an unlinked child key failed. Retry the request; if the error persists, verify that the child key's translations are not locked or in a state that prevents edits. + content: + application/json: + schema: + type: object + title: key_links/batch_destroy/error + properties: + message: + type: string + description: Human-readable error summary. + errors: + type: array + items: + type: object + title: key_links/batch_destroy/error_item + properties: + resource: + type: string + field: + type: string + message: + type: string + code: + type: string + description: Machine-readable UPPER_SNAKE_CASE error code identifying the failure reason. + enum: + - KEY_IS_NOT_LINKED + - CREATING_OR_UPDATING_TRANSLATION_ERROR + example: + message: "Validation failed" + errors: + - resource: "base" + field: "" + message: "Key feature.subtitle is not linked to main.title" + code: "KEY_IS_NOT_LINKED" '429': + description: Returned when the rate limit is exceeded. Wait until the time indicated by the X-Rate-Limit-Reset header before retrying. "$ref": "../../responses.yaml#/429" +x-code-samples: + - lang: Curl + source: |- + curl "https://api.phrase.com/v2/projects/:project_id/keys/:id/key_links" \ + -u USERNAME_OR_ACCESS_TOKEN \ + -X DELETE \ + -H "Content-Type: application/json" \ + -d '{"child_key_ids": ["feature.subtitle", "nav.home"], "strategy": "keep_content"}' + + Response (HTTP 200): + { + "created_at": "2024-03-15T10:30:00.000Z", + "updated_at": "2024-03-15T12:45:00.000Z", + "created_by": { + "id": "abcd1234efgh5678", + "username": "alice", + "name": "Alice Smith", + "gravatar_uid": "efgh5678abcd1234" + }, + "updated_by": { + "id": "ijkl9012mnop3456", + "username": "bob", + "name": "Bob Jones", + "gravatar_uid": "mnop3456ijkl9012" + }, + "account": { + "id": "qrst7890uvwx1234", + "name": "Acme Corp", + "slug": "acme-corp", + "company": "Acme Corporation", + "created_at": "2023-01-01T00:00:00.000Z", + "updated_at": "2024-03-15T12:45:00.000Z", + "company_logo_url": "https://assets.phrase.com/accounts/acme-corp/logo.png" + }, + "parent": { + "id": "main.title", + "name": "main.title", + "plural": false, + "use_ordinal_rules": false, + "data_type": "string", + "tags": ["ui", "homepage"] + }, + "children": [ + { + "id": "feature.subtitle", + "name": "feature.subtitle", + "plural": false, + "use_ordinal_rules": false, + "data_type": "string", + "tags": [] + } + ] + } From 6f9da3daca3c9b402f6159e271732adfa682b69b Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Wed, 17 Jun 2026 21:17:03 +0100 Subject: [PATCH 2/7] fix(API): clean up delete /projects/{project_id}/keys/{id}/key_links Apply the batch review conventions: - Trim the scope/status sentence from the description (write-permission, 'returns 403 on a branch', 'returns 422 KEY_IS_NOT_LINKED'); the 403 and 422 responses already document these. Keep the main-project restriction and the error-code-format note. - Drop the 'Response (HTTP 200): {...}' trailer from the curl sample. Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/compiled.json | 4 +-- paths/key_links/batch_destroy.yaml | 47 +----------------------------- 2 files changed, 3 insertions(+), 48 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index a177bdc4..45f590bb 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -30804,7 +30804,7 @@ "/projects/{project_id}/keys/{id}/key_links": { "delete": { "summary": "Batch unlink child keys from a parent key", - "description": "Removes one or more child keys from a parent key's linked-key group, or dissolves the entire group by setting unlink_parent to true.\n\nUse this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content).\n\nThis operation requires write permission on the linked-key resource and is only available on main projects; calling it against a branch project returns 403. Specifying a child key that is not currently linked to the given parent returns 422 with error code KEY_IS_NOT_LINKED. Error codes follow UPPER_SNAKE_CASE format throughout this API.\n", + "description": "Removes one or more child keys from a parent key's linked-key group, or dissolves the entire group by setting unlink_parent to true.\n\nUse this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content).\n\nThis operation is only available on main projects. Error codes follow UPPER_SNAKE_CASE format throughout this API.\n", "operationId": "key_links/batch_destroy", "tags": [ "Linked Keys" @@ -31146,7 +31146,7 @@ "x-code-samples": [ { "lang": "Curl", - "source": "curl \"https://api.phrase.com/v2/projects/:project_id/keys/:id/key_links\" \\\n -u USERNAME_OR_ACCESS_TOKEN \\\n -X DELETE \\\n -H \"Content-Type: application/json\" \\\n -d '{\"child_key_ids\": [\"feature.subtitle\", \"nav.home\"], \"strategy\": \"keep_content\"}'\n\nResponse (HTTP 200):\n{\n \"created_at\": \"2024-03-15T10:30:00.000Z\",\n \"updated_at\": \"2024-03-15T12:45:00.000Z\",\n \"created_by\": {\n \"id\": \"abcd1234efgh5678\",\n \"username\": \"alice\",\n \"name\": \"Alice Smith\",\n \"gravatar_uid\": \"efgh5678abcd1234\"\n },\n \"updated_by\": {\n \"id\": \"ijkl9012mnop3456\",\n \"username\": \"bob\",\n \"name\": \"Bob Jones\",\n \"gravatar_uid\": \"mnop3456ijkl9012\"\n },\n \"account\": {\n \"id\": \"qrst7890uvwx1234\",\n \"name\": \"Acme Corp\",\n \"slug\": \"acme-corp\",\n \"company\": \"Acme Corporation\",\n \"created_at\": \"2023-01-01T00:00:00.000Z\",\n \"updated_at\": \"2024-03-15T12:45:00.000Z\",\n \"company_logo_url\": \"https://assets.phrase.com/accounts/acme-corp/logo.png\"\n },\n \"parent\": {\n \"id\": \"main.title\",\n \"name\": \"main.title\",\n \"plural\": false,\n \"use_ordinal_rules\": false,\n \"data_type\": \"string\",\n \"tags\": [\"ui\", \"homepage\"]\n },\n \"children\": [\n {\n \"id\": \"feature.subtitle\",\n \"name\": \"feature.subtitle\",\n \"plural\": false,\n \"use_ordinal_rules\": false,\n \"data_type\": \"string\",\n \"tags\": []\n }\n ]\n}" + "source": "curl \"https://api.phrase.com/v2/projects/:project_id/keys/:id/key_links\" \\\n -u USERNAME_OR_ACCESS_TOKEN \\\n -X DELETE \\\n -H \"Content-Type: application/json\" \\\n -d '{\"child_key_ids\": [\"feature.subtitle\", \"nav.home\"], \"strategy\": \"keep_content\"}'" } ] }, diff --git a/paths/key_links/batch_destroy.yaml b/paths/key_links/batch_destroy.yaml index d3bcdb0c..cd51c0e4 100644 --- a/paths/key_links/batch_destroy.yaml +++ b/paths/key_links/batch_destroy.yaml @@ -4,7 +4,7 @@ description: | Use this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content). - This operation requires write permission on the linked-key resource and is only available on main projects; calling it against a branch project returns 403. Specifying a child key that is not currently linked to the given parent returns 422 with error code KEY_IS_NOT_LINKED. Error codes follow UPPER_SNAKE_CASE format throughout this API. + This operation is only available on main projects. Error codes follow UPPER_SNAKE_CASE format throughout this API. operationId: key_links/batch_destroy tags: - Linked Keys @@ -255,48 +255,3 @@ x-code-samples: -X DELETE \ -H "Content-Type: application/json" \ -d '{"child_key_ids": ["feature.subtitle", "nav.home"], "strategy": "keep_content"}' - - Response (HTTP 200): - { - "created_at": "2024-03-15T10:30:00.000Z", - "updated_at": "2024-03-15T12:45:00.000Z", - "created_by": { - "id": "abcd1234efgh5678", - "username": "alice", - "name": "Alice Smith", - "gravatar_uid": "efgh5678abcd1234" - }, - "updated_by": { - "id": "ijkl9012mnop3456", - "username": "bob", - "name": "Bob Jones", - "gravatar_uid": "mnop3456ijkl9012" - }, - "account": { - "id": "qrst7890uvwx1234", - "name": "Acme Corp", - "slug": "acme-corp", - "company": "Acme Corporation", - "created_at": "2023-01-01T00:00:00.000Z", - "updated_at": "2024-03-15T12:45:00.000Z", - "company_logo_url": "https://assets.phrase.com/accounts/acme-corp/logo.png" - }, - "parent": { - "id": "main.title", - "name": "main.title", - "plural": false, - "use_ordinal_rules": false, - "data_type": "string", - "tags": ["ui", "homepage"] - }, - "children": [ - { - "id": "feature.subtitle", - "name": "feature.subtitle", - "plural": false, - "use_ordinal_rules": false, - "data_type": "string", - "tags": [] - } - ] - } From 82e1a266cdfbb8f5a4e01c7a6fc05d8ea140683f Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Wed, 24 Jun 2026 09:09:51 +0200 Subject: [PATCH 3/7] docs(API): move error-response prose to shared responses.yaml Review feedback: error response descriptions should stay in the shared responses.yaml for consistency, not be re-authored inline per operation. Under OpenAPI 3.0 a description sibling of $ref is ignored anyway, so the inline text never rendered. Strip the inline $ref-sibling response descriptions (now bare $refs); the shared response owns the wording. Genuinely custom (non-$ref) response bodies are left intact. Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/compiled.json | 5 ----- paths/key_links/batch_destroy.yaml | 8 -------- 2 files changed, 13 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index 45f590bb..b641b2eb 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -31069,19 +31069,15 @@ } }, "400": { - "description": "Returned when a request parameter cannot be parsed or is structurally invalid. Correct the request body or query parameters and retry.", "$ref": "#/components/responses/400" }, "401": { - "description": "Returned when the access token is missing or invalid. Provide a valid token with the write scope and retry.", "$ref": "#/components/responses/401" }, "403": { - "description": "Returned when the caller lacks write permission on the linked-key resource, or when the target project is a branch rather than a main project. To resolve, verify that the access token carries the write scope and that the operation targets a main project.\n\nMachine-readable code: FORBIDDEN\n", "$ref": "#/components/responses/403" }, "404": { - "description": "Returned when no key matching the given id exists in the project. Verify the key code and project identifier and retry.", "$ref": "#/components/responses/404" }, "422": { @@ -31139,7 +31135,6 @@ } }, "429": { - "description": "Returned when the rate limit is exceeded. Wait until the time indicated by the X-Rate-Limit-Reset header before retrying.", "$ref": "#/components/responses/429" } }, diff --git a/paths/key_links/batch_destroy.yaml b/paths/key_links/batch_destroy.yaml index cd51c0e4..66e95cf2 100644 --- a/paths/key_links/batch_destroy.yaml +++ b/paths/key_links/batch_destroy.yaml @@ -189,19 +189,12 @@ responses: data_type: "string" tags: [] '400': - description: Returned when a request parameter cannot be parsed or is structurally invalid. Correct the request body or query parameters and retry. "$ref": "../../responses.yaml#/400" '401': - description: Returned when the access token is missing or invalid. Provide a valid token with the write scope and retry. "$ref": "../../responses.yaml#/401" '403': - description: | - Returned when the caller lacks write permission on the linked-key resource, or when the target project is a branch rather than a main project. To resolve, verify that the access token carries the write scope and that the operation targets a main project. - - Machine-readable code: FORBIDDEN "$ref": "../../responses.yaml#/403" '404': - description: Returned when no key matching the given id exists in the project. Verify the key code and project identifier and retry. "$ref": "../../responses.yaml#/404" '422': description: | @@ -245,7 +238,6 @@ responses: message: "Key feature.subtitle is not linked to main.title" code: "KEY_IS_NOT_LINKED" '429': - description: Returned when the rate limit is exceeded. Wait until the time indicated by the X-Rate-Limit-Reset header before retrying. "$ref": "../../responses.yaml#/429" x-code-samples: - lang: Curl From 0623dd0818a8239ab639ac96da6c01d6b9c03d2f Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Wed, 24 Jun 2026 09:47:48 +0200 Subject: [PATCH 4/7] docs(API): drop fabricated error codes, use shared 422 response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source walk (strings-app linked_keys_controller#batch_destroy → errors_for) confirms the 422 body is { message, errors: [{ resource, field, message }] } with NO code field. The custom 422 here invented a machine-readable UPPER_SNAKE_CASE `code` field (KEY_IS_NOT_LINKED, CREATING_OR_UPDATING_ TRANSLATION_ERROR) that the API does not emit. Replace the custom body with the shared $ref (which already documents the real envelope) and move the genuine cause to the operation description, without inventing codes. Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/compiled.json | 55 ++---------------------------- paths/key_links/batch_destroy.yaml | 43 ++--------------------- 2 files changed, 4 insertions(+), 94 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index b641b2eb..55198555 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -30804,7 +30804,7 @@ "/projects/{project_id}/keys/{id}/key_links": { "delete": { "summary": "Batch unlink child keys from a parent key", - "description": "Removes one or more child keys from a parent key's linked-key group, or dissolves the entire group by setting unlink_parent to true.\n\nUse this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content).\n\nThis operation is only available on main projects. Error codes follow UPPER_SNAKE_CASE format throughout this API.\n", + "description": "Removes one or more child keys from a parent key's linked-key group, or dissolves the entire group by setting unlink_parent to true.\n\nUse this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content).\n\nThis operation is only available on main projects. It returns 422 when a child key in `child_key_ids` is not currently linked to the parent, or when a translation update fails while unlinking.\n", "operationId": "key_links/batch_destroy", "tags": [ "Linked Keys" @@ -31081,58 +31081,7 @@ "$ref": "#/components/responses/404" }, "422": { - "description": "Returned when validation fails. All error codes follow UPPER_SNAKE_CASE format.\n\nCommon codes:\n- KEY_IS_NOT_LINKED: a key in child_key_ids is not currently linked to the specified parent key. Verify the child key codes and the parent key before retrying.\n- CREATING_OR_UPDATING_TRANSLATION_ERROR: a translation update for an unlinked child key failed. Retry the request; if the error persists, verify that the child key's translations are not locked or in a state that prevents edits.\n", - "content": { - "application/json": { - "schema": { - "type": "object", - "title": "key_links/batch_destroy/error", - "properties": { - "message": { - "type": "string", - "description": "Human-readable error summary." - }, - "errors": { - "type": "array", - "items": { - "type": "object", - "title": "key_links/batch_destroy/error_item", - "properties": { - "resource": { - "type": "string" - }, - "field": { - "type": "string" - }, - "message": { - "type": "string" - }, - "code": { - "type": "string", - "description": "Machine-readable UPPER_SNAKE_CASE error code identifying the failure reason.", - "enum": [ - "KEY_IS_NOT_LINKED", - "CREATING_OR_UPDATING_TRANSLATION_ERROR" - ] - } - } - } - } - } - }, - "example": { - "message": "Validation failed", - "errors": [ - { - "resource": "base", - "field": "", - "message": "Key feature.subtitle is not linked to main.title", - "code": "KEY_IS_NOT_LINKED" - } - ] - } - } - } + "$ref": "#/components/responses/422" }, "429": { "$ref": "#/components/responses/429" diff --git a/paths/key_links/batch_destroy.yaml b/paths/key_links/batch_destroy.yaml index 66e95cf2..1836a54c 100644 --- a/paths/key_links/batch_destroy.yaml +++ b/paths/key_links/batch_destroy.yaml @@ -4,7 +4,7 @@ description: | Use this when you need to detach specific child keys from a shared translation source, or to fully break apart a linked-key group so each key manages its own translations independently. When child keys are unlinked, their translations are updated with a copy of the parent's current content (strategy keep_content, the default) or cleared (strategy remove_content). - This operation is only available on main projects. Error codes follow UPPER_SNAKE_CASE format throughout this API. + This operation is only available on main projects. It returns 422 when a child key in `child_key_ids` is not currently linked to the parent, or when a translation update fails while unlinking. operationId: key_links/batch_destroy tags: - Linked Keys @@ -197,46 +197,7 @@ responses: '404': "$ref": "../../responses.yaml#/404" '422': - description: | - Returned when validation fails. All error codes follow UPPER_SNAKE_CASE format. - - Common codes: - - KEY_IS_NOT_LINKED: a key in child_key_ids is not currently linked to the specified parent key. Verify the child key codes and the parent key before retrying. - - CREATING_OR_UPDATING_TRANSLATION_ERROR: a translation update for an unlinked child key failed. Retry the request; if the error persists, verify that the child key's translations are not locked or in a state that prevents edits. - content: - application/json: - schema: - type: object - title: key_links/batch_destroy/error - properties: - message: - type: string - description: Human-readable error summary. - errors: - type: array - items: - type: object - title: key_links/batch_destroy/error_item - properties: - resource: - type: string - field: - type: string - message: - type: string - code: - type: string - description: Machine-readable UPPER_SNAKE_CASE error code identifying the failure reason. - enum: - - KEY_IS_NOT_LINKED - - CREATING_OR_UPDATING_TRANSLATION_ERROR - example: - message: "Validation failed" - errors: - - resource: "base" - field: "" - message: "Key feature.subtitle is not linked to main.title" - code: "KEY_IS_NOT_LINKED" + "$ref": "../../responses.yaml#/422" '429': "$ref": "../../responses.yaml#/429" x-code-samples: From 8c86570d2eebb2997536a7ee44e645b540851d5f Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Thu, 25 Jun 2026 13:20:20 +0200 Subject: [PATCH 5/7] fix(API): reference shared key_link schema in batch_destroy response Address @jablan's review: the 200 response inlined a full `linked_keys_reference` object that duplicated the existing `schemas/key_link.yaml#/key_link` model. The batch-unlink response is the same linked-key-group resource that create and list already return, so reference the shared schema instead of restating its shape. The operation-level `example:` stays inline because it illustrates the operation-specific post-unlink state (the remaining children after a child is detached), which differs from the create example. Co-Authored-By: Claude Opus 4.8 (1M context) --- paths/key_links/batch_destroy.yaml | 108 +---------------------------- 1 file changed, 1 insertion(+), 107 deletions(-) diff --git a/paths/key_links/batch_destroy.yaml b/paths/key_links/batch_destroy.yaml index 1836a54c..3226fea0 100644 --- a/paths/key_links/batch_destroy.yaml +++ b/paths/key_links/batch_destroy.yaml @@ -46,113 +46,7 @@ responses: content: application/json: schema: - title: linked_keys_reference - type: object - properties: - created_at: - type: string - format: date-time - description: When the linked-key group was created. - updated_at: - type: string - format: date-time - description: When the linked-key group was last modified. - created_by: - type: object - title: linked_keys_reference/created_by - description: User who created the linked-key group. - properties: - id: - type: string - description: User identifier (code). - username: - type: string - name: - type: string - gravatar_uid: - type: string - updated_by: - type: object - title: linked_keys_reference/updated_by - description: User who last modified the linked-key group. - properties: - id: - type: string - description: User identifier (code). - username: - type: string - name: - type: string - gravatar_uid: - type: string - account: - type: object - title: linked_keys_reference/account - description: Account the linked-key group belongs to. - properties: - id: - type: string - description: Account identifier (code). - name: - type: string - slug: - type: string - company: - type: string - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - company_logo_url: - type: string - format: uri - description: URL of the account company logo image. - parent: - type: object - title: linked_keys_reference/parent - description: The parent key that owns this linked-key group. - properties: - id: - type: string - description: Key identifier (code). - name: - type: string - plural: - type: boolean - description: Whether the key is pluralized. - use_ordinal_rules: - type: boolean - data_type: - type: string - tags: - type: array - items: - type: string - children: - type: array - description: Child keys remaining in the linked-key group after the operation. Empty when unlink_parent dissolves the group entirely. - items: - type: object - title: linked_keys_reference/child - properties: - id: - type: string - description: Key identifier (code). - name: - type: string - plural: - type: boolean - description: Whether the key is pluralized. - use_ordinal_rules: - type: boolean - data_type: - type: string - tags: - type: array - items: - type: string + "$ref": "../../schemas/key_link.yaml#/key_link" example: created_at: "2024-03-15T10:30:00.000Z" updated_at: "2024-03-15T12:45:00.000Z" From 499ecae2c0fa491f4a460ba04ca5468d16612d25 Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Thu, 25 Jun 2026 13:42:25 +0200 Subject: [PATCH 6/7] chore(spec): rebundle doc/compiled.json after the schema dedup edits Regenerated from source with `swagger-cli bundle -t json -w 300 main.yaml` (the exact command the lint/compare-output CI job runs), so the committed bundle matches a fresh bundle of the deduped YAML. Fixes the compare-output failure introduced by editing the source without rebundling. Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/compiled.json | 151 +--------------------------------------------- 1 file changed, 1 insertion(+), 150 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index b2a826cf..468d1173 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -31159,156 +31159,7 @@ "content": { "application/json": { "schema": { - "title": "linked_keys_reference", - "type": "object", - "properties": { - "created_at": { - "type": "string", - "format": "date-time", - "description": "When the linked-key group was created." - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "When the linked-key group was last modified." - }, - "created_by": { - "type": "object", - "title": "linked_keys_reference/created_by", - "description": "User who created the linked-key group.", - "properties": { - "id": { - "type": "string", - "description": "User identifier (code)." - }, - "username": { - "type": "string" - }, - "name": { - "type": "string" - }, - "gravatar_uid": { - "type": "string" - } - } - }, - "updated_by": { - "type": "object", - "title": "linked_keys_reference/updated_by", - "description": "User who last modified the linked-key group.", - "properties": { - "id": { - "type": "string", - "description": "User identifier (code)." - }, - "username": { - "type": "string" - }, - "name": { - "type": "string" - }, - "gravatar_uid": { - "type": "string" - } - } - }, - "account": { - "type": "object", - "title": "linked_keys_reference/account", - "description": "Account the linked-key group belongs to.", - "properties": { - "id": { - "type": "string", - "description": "Account identifier (code)." - }, - "name": { - "type": "string" - }, - "slug": { - "type": "string" - }, - "company": { - "type": "string" - }, - "created_at": { - "type": "string", - "format": "date-time" - }, - "updated_at": { - "type": "string", - "format": "date-time" - }, - "company_logo_url": { - "type": "string", - "format": "uri", - "description": "URL of the account company logo image." - } - } - }, - "parent": { - "type": "object", - "title": "linked_keys_reference/parent", - "description": "The parent key that owns this linked-key group.", - "properties": { - "id": { - "type": "string", - "description": "Key identifier (code)." - }, - "name": { - "type": "string" - }, - "plural": { - "type": "boolean", - "description": "Whether the key is pluralized." - }, - "use_ordinal_rules": { - "type": "boolean" - }, - "data_type": { - "type": "string" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "children": { - "type": "array", - "description": "Child keys remaining in the linked-key group after the operation. Empty when unlink_parent dissolves the group entirely.", - "items": { - "type": "object", - "title": "linked_keys_reference/child", - "properties": { - "id": { - "type": "string", - "description": "Key identifier (code)." - }, - "name": { - "type": "string" - }, - "plural": { - "type": "boolean", - "description": "Whether the key is pluralized." - }, - "use_ordinal_rules": { - "type": "boolean" - }, - "data_type": { - "type": "string" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } + "$ref": "#/components/schemas/key_link" }, "example": { "created_at": "2024-03-15T10:30:00.000Z", From fba3e687166c7c987821c31714f7a0f34d67d232 Mon Sep 17 00:00:00 2001 From: Stephen Lumenta Date: Thu, 25 Jun 2026 14:05:11 +0200 Subject: [PATCH 7/7] fix(API): centralize batch_destroy example in the shared key_link schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to @jablan's review: referencing the schema was only half of it — the 200 response still carried a large inline example that overrode the `$ref` and duplicated the shared model (with off-convention slug-style ids). Drop the inline example and put the canonical one on `schemas/key_link.yaml`, matching #1192 and #1188, so create, list, and batch unlink all render one example through the ref. Rebundled doc/compiled.json from source. Note: #1192 and #1188 make the identical addition to schemas/key_link.yaml; whichever of the three merges first wins and the others get a trivial add/add conflict on that file — keep one copy of the example. Co-Authored-By: Claude Opus 4.8 (1M context) --- doc/compiled.json | 106 ++++++++++++++++------------- paths/key_links/batch_destroy.yaml | 35 ---------- schemas/key_link.yaml | 41 +++++++++++ 3 files changed, 101 insertions(+), 81 deletions(-) diff --git a/doc/compiled.json b/doc/compiled.json index 468d1173..5352e271 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -4808,6 +4808,66 @@ }, "description": "The child translation keys linked to the parent." } + }, + "example": { + "created_at": "2024-03-15T10:22:00Z", + "updated_at": "2024-03-15T10:22:00Z", + "created_by": { + "id": "usr1a2b3c4d5e6f7a8b9c", + "username": "jane.doe", + "name": "Jane Doe", + "gravatar_uid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" + }, + "updated_by": { + "id": "usr1a2b3c4d5e6f7a8b9c", + "username": "jane.doe", + "name": "Jane Doe", + "gravatar_uid": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" + }, + "account": { + "id": "acct9z8y7x6w5v4u3t2s", + "name": "Acme Translations", + "slug": "acme-translations", + "company": "Acme Corp", + "created_at": "2023-01-10T08:00:00Z", + "updated_at": "2023-06-01T12:00:00Z", + "company_logo_url": "https://example.com/logos/acme.png" + }, + "parent": { + "id": "ijkl9012mnop3456ijkl9012", + "name": "home.hero.title", + "plural": false, + "use_ordinal_rules": false, + "data_type": "string", + "tags": [ + "ui", + "homepage" + ] + }, + "children": [ + { + "id": "ijkl9012mnop3456ijkl9012mnop3456", + "name": "home.hero.title_short", + "plural": false, + "use_ordinal_rules": false, + "data_type": "string", + "tags": [ + "ui", + "homepage" + ] + }, + { + "id": "abcd1234efgh5678abcd1234efgh5678", + "name": "home.hero.title_long", + "plural": false, + "use_ordinal_rules": false, + "data_type": "string", + "tags": [ + "ui", + "homepage" + ] + } + ] } }, "repo_sync": { @@ -31160,52 +31220,6 @@ "application/json": { "schema": { "$ref": "#/components/schemas/key_link" - }, - "example": { - "created_at": "2024-03-15T10:30:00.000Z", - "updated_at": "2024-03-15T12:45:00.000Z", - "created_by": { - "id": "abcd1234efgh5678", - "username": "alice", - "name": "Alice Smith", - "gravatar_uid": "efgh5678abcd1234" - }, - "updated_by": { - "id": "ijkl9012mnop3456", - "username": "bob", - "name": "Bob Jones", - "gravatar_uid": "mnop3456ijkl9012" - }, - "account": { - "id": "qrst7890uvwx1234", - "name": "Acme Corp", - "slug": "acme-corp", - "company": "Acme Corporation", - "created_at": "2023-01-01T00:00:00.000Z", - "updated_at": "2024-03-15T12:45:00.000Z", - "company_logo_url": "https://assets.phrase.com/accounts/acme-corp/logo.png" - }, - "parent": { - "id": "main.title", - "name": "main.title", - "plural": false, - "use_ordinal_rules": false, - "data_type": "string", - "tags": [ - "ui", - "homepage" - ] - }, - "children": [ - { - "id": "feature.subtitle", - "name": "feature.subtitle", - "plural": false, - "use_ordinal_rules": false, - "data_type": "string", - "tags": [] - } - ] } } } diff --git a/paths/key_links/batch_destroy.yaml b/paths/key_links/batch_destroy.yaml index 3226fea0..41a92cfe 100644 --- a/paths/key_links/batch_destroy.yaml +++ b/paths/key_links/batch_destroy.yaml @@ -47,41 +47,6 @@ responses: application/json: schema: "$ref": "../../schemas/key_link.yaml#/key_link" - example: - created_at: "2024-03-15T10:30:00.000Z" - updated_at: "2024-03-15T12:45:00.000Z" - created_by: - id: "abcd1234efgh5678" - username: "alice" - name: "Alice Smith" - gravatar_uid: "efgh5678abcd1234" - updated_by: - id: "ijkl9012mnop3456" - username: "bob" - name: "Bob Jones" - gravatar_uid: "mnop3456ijkl9012" - account: - id: "qrst7890uvwx1234" - name: "Acme Corp" - slug: "acme-corp" - company: "Acme Corporation" - created_at: "2023-01-01T00:00:00.000Z" - updated_at: "2024-03-15T12:45:00.000Z" - company_logo_url: "https://assets.phrase.com/accounts/acme-corp/logo.png" - parent: - id: "main.title" - name: "main.title" - plural: false - use_ordinal_rules: false - data_type: "string" - tags: ["ui", "homepage"] - children: - - id: "feature.subtitle" - name: "feature.subtitle" - plural: false - use_ordinal_rules: false - data_type: "string" - tags: [] '400': "$ref": "../../responses.yaml#/400" '401': diff --git a/schemas/key_link.yaml b/schemas/key_link.yaml index 8ec5a84f..fde3845e 100644 --- a/schemas/key_link.yaml +++ b/schemas/key_link.yaml @@ -26,3 +26,44 @@ key_link: items: $ref: "./key_preview.yaml#/key_preview" description: The child translation keys linked to the parent. + example: + created_at: "2024-03-15T10:22:00Z" + updated_at: "2024-03-15T10:22:00Z" + created_by: + id: "usr1a2b3c4d5e6f7a8b9c" + username: "jane.doe" + name: "Jane Doe" + gravatar_uid: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" + updated_by: + id: "usr1a2b3c4d5e6f7a8b9c" + username: "jane.doe" + name: "Jane Doe" + gravatar_uid: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" + account: + id: "acct9z8y7x6w5v4u3t2s" + name: "Acme Translations" + slug: "acme-translations" + company: "Acme Corp" + created_at: "2023-01-10T08:00:00Z" + updated_at: "2023-06-01T12:00:00Z" + company_logo_url: "https://example.com/logos/acme.png" + parent: + id: "ijkl9012mnop3456ijkl9012" + name: "home.hero.title" + plural: false + use_ordinal_rules: false + data_type: "string" + tags: ["ui", "homepage"] + children: + - id: "ijkl9012mnop3456ijkl9012mnop3456" + name: "home.hero.title_short" + plural: false + use_ordinal_rules: false + data_type: "string" + tags: ["ui", "homepage"] + - id: "abcd1234efgh5678abcd1234efgh5678" + name: "home.hero.title_long" + plural: false + use_ordinal_rules: false + data_type: "string" + tags: ["ui", "homepage"]