openapi: 3.2.0 info: title: Tale Platform Skills API version: 3.27.0 contact: name: Tale url: https://tale.dev description: 'REST access to a Tale deployment: knowledge resources, automations and their runs, chat threads, agents, and skills — plus an MCP endpoint exposing the same platform to MCP clients.' servers: - url: '{origin}' description: The deployment this document describes — `GET /openapi.json` on a running instance fills it in variables: origin: default: https://your-host.example.com description: Scheme and host of the Tale deployment security: - bearerAuth: [] tags: - name: Skills description: The organization’s skills. paths: /api/v1/skills: get: tags: - Skills summary: List skills description: The skills the key holder can see (their own, their teams’, the organization’s) — a complete set, not paginated. `failures` names skill bundles that could not be read. operationId: listSkills security: - bearerAuth: [] responses: '200': description: The organization’s skills content: application/json: schema: type: object description: 'The complete set under `skills` — never paginated: no `isDone`, no cursor to follow' x-tale-pagination: none required: - skills - failures properties: skills: type: array items: $ref: '#/components/schemas/SkillSummary' failures: type: array description: Skill bundles on disk that could not be read — each names the bundle and why items: type: object required: - slug - path - message properties: slug: type: string path: type: string description: The bundle’s path inside the organization’s skills tree message: type: string headers: ETag: $ref: '#/components/headers/ETag' Cache-Control: $ref: '#/components/headers/CacheControl' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '304': description: Not Modified — `If-None-Match` named the current `ETag`, so the body is not sent headers: ETag: $ref: '#/components/headers/ETag' Cache-Control: $ref: '#/components/headers/CacheControl' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '400': description: 'Invalid request: a body the schema refuses — a wrong type, an unknown key, a missing field, a NUL or an unpaired surrogate, a whole number beyond 2^53 − 1 (`INVALID_BODY`, every problem under `data.issues`); a query parameter the operation does not take, given twice or left blank (`INVALID_QUERY`); on a list, a `limit` that is not a whole number (`INVALID_LIMIT`) or a `cursor` this list did not answer (`INVALID_CURSOR`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '401': description: Missing or invalid API key (`UNAUTHORIZED`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' WWW-Authenticate: $ref: '#/components/headers/WWWAuthenticate' '403': description: '`X-Organization-Slug` names an organization the key holder is no member of (`ORG_FORBIDDEN`, with the slugs the key holder may send under `data.organizations`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '404': description: '`X-Organization-Slug` names no organization (`ORG_SLUG_INVALID`, with the slugs the key holder may send under `data.organizations`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '405': description: The path exists, but not for this method (`METHOD_NOT_ALLOWED`); `Allow` names the methods it serves content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Allow: $ref: '#/components/headers/Allow' '429': description: 'The key holder’s request budget is spent (`RATE_LIMITED`): `Retry-After` names the wait in whole seconds and `data.retryAfterMs` in milliseconds; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' '500': description: Internal error (`INTERNAL_ERROR`); the envelope carries a `requestId` to quote when reporting it content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '503': description: 'The platform’s database is restarting or cannot be reached (`DATABASE_UNAVAILABLE`): `Retry-After` names the wait in whole seconds — retry with backoff; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' parameters: - name: X-Organization-Slug in: header required: false schema: type: string description: The organization to operate on. STRICTLY REQUIRED on every call, reads included, when the key holder belongs to more than one organization — without it such requests are refused with 400 `ORG_SLUG_REQUIRED` (the dashboard’s last-active organization never steers a machine call). A slug that names no organization answers 404 `ORG_SLUG_INVALID`, one the key holder is no member of 403 `ORG_FORBIDDEN`. Single-organization keys may omit it; a blank or whitespace-only value reads as the header absent. Each of the three refusals lists the slugs the key holder may send under `data.organizations`; `GET /api/v1/me` answers them too. - name: X-Request-Id in: header required: false description: 'Your own correlation id, echoed back on the response and written to the platform’s log: up to 255 characters of letters, digits, `_`, `-` and `=`. Any other value is replaced by a fresh UUID (the response carries the id that was used), and uniqueness of an id you choose is yours to keep.' schema: type: string pattern: ^[A-Za-z0-9_=-]{1,255}$ /api/v1/skills/{slug}: get: tags: - Skills summary: Get skill operationId: getSkill description: 'One skill bundle: the summary fields plus the body and the file list, with the document’s entity tag as `ETag` — send it back as `If-Match` on a save, or as `If-None-Match` on the next read to get 304 while the document is unchanged. The tag covers the SKILL.md content only: `canEdit`, `ownerName`, `updatedBy` and `updatedByName` can change while it stands (a member leaves or is renamed, an edit changes only the sharing), so a 304 does not revalidate them — read without `If-None-Match` when you need them current. A malformed slug answers 404 like an unknown one.' security: - bearerAuth: [] parameters: - name: X-Organization-Slug in: header required: false schema: type: string description: The organization to operate on. STRICTLY REQUIRED on every call, reads included, when the key holder belongs to more than one organization — without it such requests are refused with 400 `ORG_SLUG_REQUIRED` (the dashboard’s last-active organization never steers a machine call). A slug that names no organization answers 404 `ORG_SLUG_INVALID`, one the key holder is no member of 403 `ORG_FORBIDDEN`. Single-organization keys may omit it; a blank or whitespace-only value reads as the header absent. Each of the three refusals lists the slugs the key holder may send under `data.organizations`; `GET /api/v1/me` answers them too. - name: slug in: path required: true schema: type: string pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ maxLength: 64 description: The skill slug — at most 64 characters of lowercase letters, digits and single hyphens; `anthropic` and `claude` are reserved. Reads and the delete answer a malformed slug as absent (404 `SKILL_NOT_FOUND`); the save refuses it with 400 `INVALID_SKILL_SLUG`, naming the rule it breaks. - name: If-None-Match in: header required: false schema: type: string description: 'The `etag` you hold (or a list, or `*`): when it names the current document — weak comparison, so a `W/` prefix counts — the answer is 304 with the tag and no body' - name: X-Request-Id in: header required: false description: 'Your own correlation id, echoed back on the response and written to the platform’s log: up to 255 characters of letters, digits, `_`, `-` and `=`. Any other value is replaced by a fresh UUID (the response carries the id that was used), and uniqueness of an id you choose is yours to keep.' schema: type: string pattern: ^[A-Za-z0-9_=-]{1,255}$ responses: '200': description: The skill content: application/json: schema: $ref: '#/components/schemas/Skill' headers: ETag: $ref: '#/components/headers/ETag' Cache-Control: $ref: '#/components/headers/CacheControl' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '304': description: 'Not modified: `If-None-Match` named the current document (weakly — the `W/` and the edge-suffixed `"…-gzip"` forms match); `ETag` repeats the tag, `Cache-Control` says `private, no-cache` as the 200 does, no body' headers: ETag: $ref: '#/components/headers/ETag' Cache-Control: $ref: '#/components/headers/CacheControl' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '400': description: 'Invalid request: a body the schema refuses — a wrong type, an unknown key, a missing field, a NUL or an unpaired surrogate, a whole number beyond 2^53 − 1 (`INVALID_BODY`, every problem under `data.issues`); a query parameter the operation does not take, given twice or left blank (`INVALID_QUERY`); on a list, a `limit` that is not a whole number (`INVALID_LIMIT`) or a `cursor` this list did not answer (`INVALID_CURSOR`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '401': description: Missing or invalid API key (`UNAUTHORIZED`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' WWW-Authenticate: $ref: '#/components/headers/WWWAuthenticate' '403': description: '`X-Organization-Slug` names an organization the key holder is no member of (`ORG_FORBIDDEN`, with the slugs the key holder may send under `data.organizations`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '404': description: No such skill, none this key may see, or a malformed slug (`SKILL_NOT_FOUND`); or `X-Organization-Slug` names no organization (`ORG_SLUG_INVALID`, with the slugs the key holder may send under `data.organizations`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '405': description: The path exists, but not for this method (`METHOD_NOT_ALLOWED`); `Allow` names the methods it serves content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Allow: $ref: '#/components/headers/Allow' '429': description: 'The key holder’s request budget is spent (`RATE_LIMITED`): `Retry-After` names the wait in whole seconds and `data.retryAfterMs` in milliseconds; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' '500': description: Internal error (`INTERNAL_ERROR`); the envelope carries a `requestId` to quote when reporting it content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '503': description: 'The platform’s database is restarting or cannot be reached (`DATABASE_UNAVAILABLE`): `Retry-After` names the wait in whole seconds — retry with backoff; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' put: tags: - Skills summary: Create or update skill description: 'Creates the bundle when the slug is free — **201** — and updates it in place otherwise — **200** — so the status is the create-or-update signal (the same convention as a task materialisation) and a sync that mirrors bundles from elsewhere needs no read first: `description` and `body` are required; an omitted `icon`, `labels`, `teams`, `visibility` or `disableModelInvocation` keeps its stored value, `null` clears `icon` or `labels`, and `disableModelInvocation: false` drops the flag. A body that does not end with a newline gets one appended. The save rewrites `SKILL.md` only — every other file of the bundle stays, and frontmatter keys the body does not carry (`license`, `recommended-packages`, community keys) are preserved; replacing a whole bundle is the app’s zip upload. Guard an update with `If-Match`: the `etag` you last read (the GET’s `ETag`) — a document that changed since, or is not there, answers 412 `SKILL_STALE` with the current tag in `data.etag` and nothing is written. Send `If-None-Match: *` to create only — a slug that already has a bundle then answers 412 `SKILL_EXISTS` and nothing is written. The body is validated before the preconditions are evaluated. A save whose composed `SKILL.md` is byte-identical to the stored document writes nothing — 200 with the stored `etag` and `updatedAt`, no history entry — the preconditions still evaluated first, so a stale `If-Match` on an identical body is still 412. Every skill carries `canEdit`: whether this key may edit the bundle; shipped skills are organization bundles an administrator may overwrite, so check it before a save that means to replace one. A save that changes the document is recorded in the organization’s audit log as the key’s user — `skill.created`, `skill.updated`, and `skill.sharing_changed` when `visibility` or `teams` moved — and an update makes that user the skill’s `updatedBy`; a save that writes nothing records nothing. An organization may reserve organization-wide skills (its `skill_sharing` policy: Editors and above, or owners and administrators, plus members granted `tale:skills.publish`): a key holder outside that set gets 403 `SKILL_PUBLISH_FORBIDDEN` for a save that would create a `visibility: org` skill, widen one to `org`, or change an `org` skill in place, and the refusal is audited as `skill.publish_denied`; narrowing to `team`, a byte-identical save and deleting the skill stay open, and `GET /api/v1/me` answers `capabilities.skillPublish`. The body may run to 4 MiB — this operation’s own cap, so the worst JSON escaping of a full-size `body` still fits; past it the answer is 413 `BODY_TOO_LARGE`.' operationId: saveSkill security: - bearerAuth: [] parameters: - name: X-Organization-Slug in: header required: false schema: type: string description: The organization to operate on. STRICTLY REQUIRED on every call, reads included, when the key holder belongs to more than one organization — without it such requests are refused with 400 `ORG_SLUG_REQUIRED` (the dashboard’s last-active organization never steers a machine call). A slug that names no organization answers 404 `ORG_SLUG_INVALID`, one the key holder is no member of 403 `ORG_FORBIDDEN`. Single-organization keys may omit it; a blank or whitespace-only value reads as the header absent. Each of the three refusals lists the slugs the key holder may send under `data.organizations`; `GET /api/v1/me` answers them too. - name: slug in: path required: true schema: type: string pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ maxLength: 64 description: The skill slug — at most 64 characters of lowercase letters, digits and single hyphens; `anthropic` and `claude` are reserved. Reads and the delete answer a malformed slug as absent (404 `SKILL_NOT_FOUND`); the save refuses it with 400 `INVALID_SKILL_SLUG`, naming the rule it breaks. - name: If-Match in: header required: false schema: type: string description: 'The `etag` you last read — strong comparison, so a `W/` tag never matches — or `*`: the save proceeds only when the stored SKILL.md still carries that tag (`*`: when one is stored at all); otherwise 412 `SKILL_STALE`, `data.etag` naming the current tag (`null` when nothing is stored), nothing written. Evaluated before `If-None-Match`, inside the same lock as the write.' - name: If-None-Match in: header required: false schema: type: string description: 'Send `*` to create only: a slug that already has a bundle answers 412 `SKILL_EXISTS` and nothing is written. A tag list refuses the same way when the stored document weakly matches one of its tags (its current `etag`, with or without `W/`); any other value matches nothing and the write goes ahead.' - name: X-Request-Id in: header required: false description: 'Your own correlation id, echoed back on the response and written to the platform’s log: up to 255 characters of letters, digits, `_`, `-` and `=`. Any other value is replaced by a fresh UUID (the response carries the id that was used), and uniqueness of an id you choose is yours to keep.' schema: type: string pattern: ^[A-Za-z0-9_=-]{1,255}$ requestBody: required: true content: application/json: schema: type: object required: - description - body additionalProperties: false properties: description: type: string minLength: 1 maxLength: 1024 body: type: string maxLength: 507893 description: 'Markdown, at most 507893 bytes of UTF-8 (bytes, not characters — the maxLength here is the byte budget): the composed SKILL.md, frontmatter included, is capped at 512 KiB, and this budget always fits inside it' visibility: type: string enum: - team - org description: 'Who sees the skill; omitted keeps the stored value (a new skill is `org`, which an organization that reserves organization-wide skills refuses with 403 `SKILL_PUBLISH_FORBIDDEN` when the key holder may not publish — send `team` with `teams` instead). `private` is retired: it cannot be set, only kept by omission on a bundle that already carries it' teams: type: array items: type: string minLength: 1 maxLength: 128 maxItems: 32 description: Team ids a `team` skill is shared with; each must be a team of this organization (400 `SKILL_TEAM_UNKNOWN` otherwise) icon: type: - string - 'null' maxLength: 128 description: An Iconify id (`lucide:book-open`); `null` clears it, omitted keeps it labels: type: - array - 'null' items: type: string minLength: 1 maxLength: 40 maxItems: 8 description: '`null` clears them, omitted keeps them' disableModelInvocation: type: boolean description: True keeps the model from reaching for the skill on its own (it stays available by explicit name); omitted keeps the stored value, `false` drops the flag responses: '200': description: The skill this save updated in place — its `etag` names the version just written, or the stored one when the body changed nothing (then `updatedAt` stays too) content: application/json: schema: $ref: '#/components/schemas/Skill' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '201': description: The skill this save created (the slug was free) — its `etag` names the version just written content: application/json: schema: $ref: '#/components/schemas/Skill' headers: Location: $ref: '#/components/headers/Location' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '400': description: Invalid body (`INVALID_BODY` — an unknown key, a body over the byte budget, a visibility outside `team`/`org`), a malformed slug (`INVALID_SKILL_SLUG`, naming the rule it breaks), an invalid skill (`INVALID_SKILL`), or a team id the organization does not have (`SKILL_TEAM_UNKNOWN`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '401': description: Missing or invalid API key (`UNAUTHORIZED`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' WWW-Authenticate: $ref: '#/components/headers/WWWAuthenticate' '403': description: Not editable with this key (`SKILL_FORBIDDEN`), a team this key holder is not in (`TEAM_ACCESS_DENIED`), or an organization-wide skill the organization reserves and this key holder may not publish (`SKILL_PUBLISH_FORBIDDEN` — see `capabilities.skillPublish` on `GET /api/v1/me`); or `X-Organization-Slug` names an organization the key holder is no member of (`ORG_FORBIDDEN`, with the slugs the key holder may send under `data.organizations`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '404': description: '`X-Organization-Slug` names no organization (`ORG_SLUG_INVALID`, with the slugs the key holder may send under `data.organizations`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '405': description: The path exists, but not for this method (`METHOD_NOT_ALLOWED`); `Allow` names the methods it serves content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Allow: $ref: '#/components/headers/Allow' '412': description: 'A precondition failed and nothing was written: `If-Match` named no tag matching the stored SKILL.md, or `*` with nothing stored (`SKILL_STALE` — `data.etag` carries the current tag, `null` when nothing is stored); or `If-None-Match: *` was sent and the slug already has a bundle, or a tag list named its current tag (`SKILL_EXISTS`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '413': description: The body exceeds 4 MiB — this operation’s own cap, above the door’s 1 MiB default, so the worst JSON escaping of a full-size `body` still fits (`BODY_TOO_LARGE`); the envelope carries a `requestId` content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '422': description: The bundle already stored under the slug cannot be read — a planted symlink, a file over the 4 MiB staging cap, a `SKILL.md` that does not parse (`SKILL_MALFORMED`); never the body you send, which is refused as 400 (`INVALID_BODY`, `INVALID_SKILL`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '429': description: 'The key holder’s request budget is spent (`RATE_LIMITED`): `Retry-After` names the wait in whole seconds and `data.retryAfterMs` in milliseconds; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' '500': description: Internal error (`INTERNAL_ERROR`); the envelope carries a `requestId` to quote when reporting it content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '503': description: 'The platform’s database is restarting or cannot be reached (`DATABASE_UNAVAILABLE`): `Retry-After` names the wait in whole seconds — retry with backoff; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' delete: tags: - Skills summary: Delete skill operationId: deleteSkill description: 'Delete the bundle the slug names — its owner, or an administrator; a malformed or unknown slug answers 404 `SKILL_NOT_FOUND` (no precondition is evaluated on an absent slug). `If-Match` guards it like the save: a tag that no longer matches the stored SKILL.md answers 412 `SKILL_STALE` and the bundle stays.' security: - bearerAuth: [] parameters: - name: X-Organization-Slug in: header required: false schema: type: string description: The organization to operate on. STRICTLY REQUIRED on every call, reads included, when the key holder belongs to more than one organization — without it such requests are refused with 400 `ORG_SLUG_REQUIRED` (the dashboard’s last-active organization never steers a machine call). A slug that names no organization answers 404 `ORG_SLUG_INVALID`, one the key holder is no member of 403 `ORG_FORBIDDEN`. Single-organization keys may omit it; a blank or whitespace-only value reads as the header absent. Each of the three refusals lists the slugs the key holder may send under `data.organizations`; `GET /api/v1/me` answers them too. - name: slug in: path required: true schema: type: string pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ maxLength: 64 description: The skill slug — at most 64 characters of lowercase letters, digits and single hyphens; `anthropic` and `claude` are reserved. Reads and the delete answer a malformed slug as absent (404 `SKILL_NOT_FOUND`); the save refuses it with 400 `INVALID_SKILL_SLUG`, naming the rule it breaks. - name: If-Match in: header required: false schema: type: string description: 'The `etag` you last read, or `*`: the delete proceeds only when the stored SKILL.md still carries that tag; otherwise 412 `SKILL_STALE` with the current tag in `data.etag`' - name: If-None-Match in: header required: false schema: type: string description: 'A tag list (or `*`): the delete proceeds only when the stored document weakly matches none of them; otherwise 412 `SKILL_EXISTS`' - name: X-Request-Id in: header required: false description: 'Your own correlation id, echoed back on the response and written to the platform’s log: up to 255 characters of letters, digits, `_`, `-` and `=`. Any other value is replaced by a fresh UUID (the response carries the id that was used), and uniqueness of an id you choose is yours to keep.' schema: type: string pattern: ^[A-Za-z0-9_=-]{1,255}$ responses: '204': description: Deleted headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '400': description: 'Invalid request: a body the schema refuses — a wrong type, an unknown key, a missing field, a NUL or an unpaired surrogate, a whole number beyond 2^53 − 1 (`INVALID_BODY`, every problem under `data.issues`); a query parameter the operation does not take, given twice or left blank (`INVALID_QUERY`); on a list, a `limit` that is not a whole number (`INVALID_LIMIT`) or a `cursor` this list did not answer (`INVALID_CURSOR`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '401': description: Missing or invalid API key (`UNAUTHORIZED`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' WWW-Authenticate: $ref: '#/components/headers/WWWAuthenticate' '403': description: Not deletable with this key (`SKILL_FORBIDDEN`); or `X-Organization-Slug` names an organization the key holder is no member of (`ORG_FORBIDDEN`, with the slugs the key holder may send under `data.organizations`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '404': description: No such skill, or a malformed slug (`SKILL_NOT_FOUND`); or `X-Organization-Slug` names no organization (`ORG_SLUG_INVALID`, with the slugs the key holder may send under `data.organizations`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '405': description: The path exists, but not for this method (`METHOD_NOT_ALLOWED`); `Allow` names the methods it serves content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Allow: $ref: '#/components/headers/Allow' '412': description: 'A precondition failed and the bundle stays: `If-Match` named no tag matching the stored SKILL.md (`SKILL_STALE`, `data.etag` carries the current tag), or `If-None-Match` named it (`SKILL_EXISTS`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '429': description: 'The key holder’s request budget is spent (`RATE_LIMITED`): `Retry-After` names the wait in whole seconds and `data.retryAfterMs` in milliseconds; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' '500': description: Internal error (`INTERNAL_ERROR`); the envelope carries a `requestId` to quote when reporting it content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '503': description: 'The platform’s database is restarting or cannot be reached (`DATABASE_UNAVAILABLE`): `Retry-After` names the wait in whole seconds — retry with backoff; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' /api/v1/skills/{slug}/files/{path}: get: tags: - Skills summary: Download a bundle file operationId: downloadSkillFile description: 'The bytes of one file of the bundle — `SKILL.md` included — exactly as the organization’s tree holds it: `application/octet-stream`, `Content-Length`, the file’s own name in an RFC 6266 `Content-Disposition`, private and uncacheable; a HEAD request answers the headers alone. The skill’s `files[]` is the only legitimate source of paths: a path it would never list — a traversal, a dot-entry, `node_modules/…` — reads as a file the bundle does not have (404 `SKILL_FILE_NOT_FOUND`), where an unknown, invisible or malformed slug is 404 `SKILL_NOT_FOUND`. A raw dot-segment in the URL (`../`, or `%2e%2e/` — the dots encoded, the slash not) never reaches this operation: the edge refuses it first with its own 404 `NOT_FOUND`, without `X-Tale-Api-Version`; a spelling whose slashes are encoded too (`%2e%2e%2f…`) does, and reads as `SKILL_FILE_NOT_FOUND`. A bundle the file layer refuses to read — a planted symlink, a file over the 4 MiB staging cap — answers 422 `SKILL_MALFORMED`.' security: - bearerAuth: [] parameters: - name: X-Organization-Slug in: header required: false schema: type: string description: The organization to operate on. STRICTLY REQUIRED on every call, reads included, when the key holder belongs to more than one organization — without it such requests are refused with 400 `ORG_SLUG_REQUIRED` (the dashboard’s last-active organization never steers a machine call). A slug that names no organization answers 404 `ORG_SLUG_INVALID`, one the key holder is no member of 403 `ORG_FORBIDDEN`. Single-organization keys may omit it; a blank or whitespace-only value reads as the header absent. Each of the three refusals lists the slugs the key holder may send under `data.organizations`; `GET /api/v1/me` answers them too. - name: slug in: path required: true schema: type: string pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ maxLength: 64 description: The skill slug — at most 64 characters of lowercase letters, digits and single hyphens; `anthropic` and `claude` are reserved. Reads and the delete answer a malformed slug as absent (404 `SKILL_NOT_FOUND`); the save refuses it with 400 `INVALID_SKILL_SLUG`, naming the rule it breaks. - name: path in: path required: true schema: type: string description: The file’s bundle-relative path exactly as `files[].path` lists it — nested segments separated by `/`, raw or percent-encoded (`%2F`) - name: If-None-Match in: header required: false schema: type: string description: 'The `ETag` a previous answer carried (the tag is over the file’s bytes; the weak `W/` form matches too): unchanged bytes answer 304 with no body. Takes precedence over `If-Modified-Since`.' - name: If-Modified-Since in: header required: false schema: type: string description: 'The `Last-Modified` a previous answer carried: a file not modified since answers 304, judged at whole-second precision. Ignored when `If-None-Match` is present.' - name: X-Request-Id in: header required: false description: 'Your own correlation id, echoed back on the response and written to the platform’s log: up to 255 characters of letters, digits, `_`, `-` and `=`. Any other value is replaced by a fresh UUID (the response carries the id that was used), and uniqueness of an id you choose is yours to keep.' schema: type: string pattern: ^[A-Za-z0-9_=-]{1,255}$ responses: '200': description: The bytes, named by `Content-Disposition` headers: Content-Disposition: $ref: '#/components/headers/ContentDisposition' Content-Length: $ref: '#/components/headers/ContentLength' ETag: $ref: '#/components/headers/ETag' Last-Modified: $ref: '#/components/headers/LastModified' Cache-Control: $ref: '#/components/headers/CacheControl' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' content: application/octet-stream: schema: type: string format: binary '304': description: Not Modified — `If-None-Match` named the current `ETag` (or `If-Modified-Since` the current `Last-Modified`), so no bytes are sent; `ETag`, `Last-Modified` and `Cache-Control` ride along headers: ETag: $ref: '#/components/headers/ETag' Last-Modified: $ref: '#/components/headers/LastModified' Cache-Control: $ref: '#/components/headers/CacheControl' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '400': description: 'Invalid request: a body the schema refuses — a wrong type, an unknown key, a missing field, a NUL or an unpaired surrogate, a whole number beyond 2^53 − 1 (`INVALID_BODY`, every problem under `data.issues`); a query parameter the operation does not take, given twice or left blank (`INVALID_QUERY`); on a list, a `limit` that is not a whole number (`INVALID_LIMIT`) or a `cursor` this list did not answer (`INVALID_CURSOR`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '401': description: Missing or invalid API key (`UNAUTHORIZED`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' WWW-Authenticate: $ref: '#/components/headers/WWWAuthenticate' '403': description: '`X-Organization-Slug` names an organization the key holder is no member of (`ORG_FORBIDDEN`, with the slugs the key holder may send under `data.organizations`)' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '404': description: No such skill, none this key may see, or a malformed slug (`SKILL_NOT_FOUND`); or a skill without a file at that path (`SKILL_FILE_NOT_FOUND`); or `X-Organization-Slug` names no organization (`ORG_SLUG_INVALID`, with the slugs the key holder may send under `data.organizations`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '405': description: The path exists, but not for this method (`METHOD_NOT_ALLOWED`); `Allow` names the methods it serves content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Allow: $ref: '#/components/headers/Allow' '422': description: The bundle cannot be read (`SKILL_MALFORMED`) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '429': description: 'The key holder’s request budget is spent (`RATE_LIMITED`): `Retry-After` names the wait in whole seconds and `data.retryAfterMs` in milliseconds; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' '500': description: Internal error (`INTERNAL_ERROR`); the envelope carries a `requestId` to quote when reporting it content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '503': description: 'The platform’s database is restarting or cannot be reached (`DATABASE_UNAVAILABLE`): `Retry-After` names the wait in whole seconds — retry with backoff; the envelope carries a `requestId`' content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' Retry-After: $ref: '#/components/headers/RetryAfter' components: schemas: Skill: type: object description: 'The skill bundle: its summary fields plus the markdown body and the bundle’s file list' required: - slug - description - visibility - origin - canEdit - etag - updatedAt - body - files properties: slug: type: string pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ maxLength: 64 description: type: string visibility: type: string enum: - private - team - org description: '`org` — every member; `team` — members of `teams`; `private` — retired for new skills, still carried by pre-existing bundles their owner alone sees' teams: type: array items: type: string description: Team ids a `team` skill is shared with; absent otherwise owner: type: string description: The member who created the bundle, as a user id — absent when none is recorded. A skill created in the editor or uploaded belongs to the member who created it; a declared `owner` in an uploaded bundle is never honoured origin: type: string enum: - builtin - release - member description: 'Where the skill came from: `release` — a managed configuration release installed it (its frontmatter carries `metadata.tale-release`); `builtin` — no owner is recorded, as on the catalog copies an organization starts with; `member` — the member named by `owner` created it' ownerName: type: string description: The display name of `owner` (their email when they have none) while they are a member of the organization; absent once they have left, and whenever `owner` is updatedBy: type: string description: The user id of the member whose write through Tale produced the stored SKILL.md — present only when the newest recorded write of the skill is an edit whose resulting tag is the current `etag`. Absent on a skill nobody has edited since it was created, and on one changed outside Tale since its last edit updatedByName: type: string description: The display name of `updatedBy` while they are a member of the organization icon: type: string description: An Iconify id shown on the skill’s card labels: type: array items: type: string description: Display chips on the skill’s card disableModelInvocation: type: boolean description: True when the model must not reach for the skill on its own; it stays available by explicit name canEdit: type: boolean description: Whether this key may edit the bundle; shipped skills are organization bundles an administrator may overwrite etag: type: string description: The strong entity tag of the bundle’s SKILL.md — the quoted SHA-256 of its content, the `ETag` the GET carries and the value a conditional save sends back as `If-Match`. Moves with every save of the document; the bundle’s other files never move it updatedAt: type: integer minimum: 0 description: When SKILL.md was last written body: type: string description: The SKILL.md markdown after the frontmatter, as stored — always newline-terminated files: type: array description: Every file of the bundle (SKILL.md included), sorted by path items: type: object required: - path - size properties: path: type: string description: Bundle-relative POSIX path size: type: integer description: Bytes additionalProperties: false additionalProperties: false SkillSummary: type: object required: - slug - description - visibility - origin - canEdit - etag - updatedAt properties: slug: type: string pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ maxLength: 64 description: type: string visibility: type: string enum: - private - team - org description: '`org` — every member; `team` — members of `teams`; `private` — retired for new skills, still carried by pre-existing bundles their owner alone sees' teams: type: array items: type: string description: Team ids a `team` skill is shared with; absent otherwise owner: type: string description: The member who created the bundle, as a user id — absent when none is recorded. A skill created in the editor or uploaded belongs to the member who created it; a declared `owner` in an uploaded bundle is never honoured origin: type: string enum: - builtin - release - member description: 'Where the skill came from: `release` — a managed configuration release installed it (its frontmatter carries `metadata.tale-release`); `builtin` — no owner is recorded, as on the catalog copies an organization starts with; `member` — the member named by `owner` created it' ownerName: type: string description: The display name of `owner` (their email when they have none) while they are a member of the organization; absent once they have left, and whenever `owner` is updatedBy: type: string description: The user id of the member whose write through Tale produced the stored SKILL.md — present only when the newest recorded write of the skill is an edit whose resulting tag is the current `etag`. Absent on a skill nobody has edited since it was created, and on one changed outside Tale since its last edit updatedByName: type: string description: The display name of `updatedBy` while they are a member of the organization icon: type: string description: An Iconify id shown on the skill’s card labels: type: array items: type: string description: Display chips on the skill’s card disableModelInvocation: type: boolean description: True when the model must not reach for the skill on its own; it stays available by explicit name canEdit: type: boolean description: Whether this key may edit the bundle; shipped skills are organization bundles an administrator may overwrite etag: type: string description: The strong entity tag of the bundle’s SKILL.md — the quoted SHA-256 of its content, the `ETag` the GET carries and the value a conditional save sends back as `If-Match`. Moves with every save of the document; the bundle’s other files never move it updatedAt: type: integer minimum: 0 description: When SKILL.md was last written additionalProperties: false Error: type: object required: - error - code properties: error: type: string description: What went wrong code: type: string enum: - ACTOR_AMBIGUOUS - ACTOR_DISABLED - ACTOR_FORBIDDEN - ACTOR_NOT_FOUND - ACTOR_REBOUND - ACTOR_UNVERIFIED - API_KEY_SCOPE_FORBIDDEN - ATTACHMENT_NOT_FOUND - ATTACHMENT_NOT_OWNED - ATTACHMENT_NOT_STAGED - ATTACHMENT_SIZE_MISMATCH - AUTHOR_UNVERIFIED - AUTOMATION_DELIVERY_SCOPE_MISMATCH - AUTOMATION_HAS_ACTIVE_RUNS - AUTOMATION_INPUT_INVALID - AUTOMATION_NOT_DEPLOYED - AUTOMATION_NOT_FOUND - AUTOMATION_NOT_INSTALLED - AUTOMATION_PROJECT_FORBIDDEN - AUTOMATION_PROJECT_SCOPE_REQUIRED - AUTOMATION_TRIGGER_INVALID - AUTOMATION_VERSION_NOT_DEPLOYED - AUTOMATION_VERSION_UNKNOWN - BLOB_NOT_FOUND - BODY_CHUNK_MALFORMED - BODY_LENGTH_MISMATCH - BODY_TOO_LARGE - BROWSER_SESSION_NOT_FOUND - BUDGET_EXCEEDED - CHAT_MODEL_AMBIGUOUS - CHAT_MODEL_NOT_ON_PROVIDER - CHAT_MODEL_UNKNOWN - CHAT_PROVIDER_UNKNOWN - CHAT_THREAD_ARCHIVED - CHAT_THREAD_NOT_DIRECT - CHAT_TURN_IN_PROGRESS - CHAT_TURN_NOT_RUNNING - CONTACT_AMBIGUOUS - CONTACT_DUPLICATE_EMAIL - CONTACT_DUPLICATE_EXTERNAL_ID - CONTACT_IDENTITY_REQUIRED - CONTACT_NOT_FOUND - CONTACT_STALE - CONVERSATION_CLOSED - CONVERSATION_CONTACT_CONFLICT - CONVERSATION_CONTACT_TRASHED - CONVERSATION_NOT_FOUND - CONVERSATION_SNAPSHOT_CONFLICT - CONVERSATION_SOURCE_NOT_FOUND - DATABASE_UNAVAILABLE - DELIVERY_NOT_FOUND - DELIVERY_RECEIPT_CONFLICT - DELIVERY_RETRY_UNAVAILABLE - DELIVERY_UNACKNOWLEDGED - DOCUMENT_HAS_KNOWLEDGE_ENTRY - DOCUMENT_NOT_FOUND - DOCUMENT_RECORD_FROZEN - DOCUMENT_RECORD_PROTECTED - DOCUMENT_RECORD_REPLACEMENT_REQUIRED - DOCUMENT_STALE - DUPLICATE_PRODUCT_EXTERNAL_ID - DUPLICATE_PRODUCT_NAME - EMBEDDING_CREDENTIAL_REJECTED - EMBEDDING_CREDIT_EXHAUSTED - EMBEDDING_NOT_CONFIGURED - EMBEDDING_UPSTREAM_ERROR - EMPTY_ANSWER - FILE_NOT_FOUND - FILE_SIZE_INVALID - FILE_TOO_LARGE - FOLDER_DEPTH_EXCEEDED - FOLDER_NAME_INVALID - FOLDER_NAME_TAKEN - FOLDER_NOT_ACCESSIBLE - FOLDER_NOT_FOUND - FORBIDDEN_DEPLOYMENT_EDITOR - FORBIDDEN_INSTANCE_ADMIN - HTTP_ERROR - HUMAN_ASK_EXPIRED - HUMAN_ASK_NOT_FOUND - HUMAN_ASK_NOT_PENDING - IDEMPOTENCY_KEY_REUSED - INTEGRATION_NOT_OWNED - INTERNAL_ERROR - INVALID_BODY - INVALID_CURSOR - INVALID_HEADER - INVALID_LIMIT - INVALID_QUERY - INVALID_SESSION - INVALID_SKILL - INVALID_SKILL_SLUG - INVALID_URL - KNOWLEDGE_ENTRY_DUPLICATE - KNOWLEDGE_ENTRY_FORBIDDEN - KNOWLEDGE_ENTRY_NOT_FOUND - KNOWLEDGE_ENTRY_STORE_TIMEOUT - KNOWLEDGE_ENTRY_SUPERSEDED - LEGAL_HOLD_ACTIVE - MENTION_DIRECTORY_UNAVAILABLE - MESSAGE_NOT_FOUND - METHOD_NOT_ALLOWED - MODEL_API_CONCURRENCY_EXCEEDED - MODEL_API_DISABLED - MODEL_API_FORBIDDEN - MODEL_API_GUARDRAIL_BLOCKED - MODEL_API_GUARDRAIL_UNAVAILABLE - MODEL_API_GUARDRAIL_UNSUPPORTED - MODEL_API_MODEL_FORBIDDEN - MODEL_API_MODEL_UNKNOWN - MODEL_API_TEXT_TOO_LARGE - MODEL_API_TOOLS_UNSUPPORTED - MODEL_API_UNAVAILABLE - MODEL_API_UPSTREAM_ERROR - MODEL_API_VENDOR_TOOL_UNSUPPORTED - MODEL_API_VISION_UNSUPPORTED - NOT_FOUND - OBJECT_STORE_UNAVAILABLE - OBJECT_STORE_UNCONFIGURED - ORG_FORBIDDEN - ORG_SLUG_INVALID - ORG_SLUG_REQUIRED - ORIGIN_FORBIDDEN - PRECONDITION_FAILED - PRODUCT_NOT_FOUND - PRODUCT_STALE - PROJECT_AGENT_CONNECTOR_UNKNOWN - PROJECT_AGENT_HARNESS_INVALID - PROJECT_AGENT_LIMIT - PROJECT_AGENT_MANAGED - PROJECT_AGENT_MODEL_INVALID - PROJECT_AGENT_NAME_TAKEN - PROJECT_AGENT_NOT_FOUND - PROJECT_AGENT_PROVIDER_UNKNOWN - PROJECT_AGENT_SECRETS_FORBIDDEN - PROJECT_AGENT_SECRET_UNKNOWN - PROJECT_AGENT_SKILL_UNKNOWN - PROJECT_AGENT_STALE - PROJECT_AGENT_TOOL_UNKNOWN - PROJECT_ARCHIVED - PROJECT_DUPLICATE_EXTERNAL_ID - PROJECT_FORBIDDEN - PROJECT_HAS_BOUND_AUTOMATIONS - PROJECT_HAS_PROTECTED_RECORDS - PROJECT_KEY_INVALID - PROJECT_KEY_TAKEN - PROJECT_LEGAL_HOLD - PROJECT_NOT_FOUND - PROJECT_SHARING_INVALID - PURGE_INCOMPLETE - RATE_LIMITED - RBAC_FORBIDDEN - REQUEST_TIMEOUT - REVIEW_COMPETENCE_REQUIRED - REVIEW_INDEPENDENT_REVIEWER_REQUIRED - ROLE_FORBIDDEN - RUN_ACTIVE - RUN_NOT_FOUND - RUN_QUARANTINED - RUN_QUARANTINE_CHANGED - SETUP_FOLDER_MISSING - SKILL_EXISTS - SKILL_FILE_NOT_FOUND - SKILL_FORBIDDEN - SKILL_MALFORMED - SKILL_NOT_FOUND - SKILL_PUBLISH_FORBIDDEN - SKILL_STALE - SKILL_TEAM_UNKNOWN - STANDARD_AGENT_OFF - STANDARD_AGENT_UNAVAILABLE - TASK_AGENT_REVIEW_REQUIRED - TASK_ARCHIVED - TASK_AUTOMATION_DISABLED - TASK_AUTOMATION_UNAVAILABLE - TASK_EXTERNAL_REF_INVALID - TASK_EXTERNAL_STATUS_STALE - TASK_HAS_LIVE_RUN - TASK_HAS_OPEN_SUBTASKS - TASK_LABEL_UNKNOWN - TASK_NOT_FOUND - TASK_NOT_IN_REVIEW - TASK_REVIEW_POLICY_UNAVAILABLE - TASK_STATUS_CONFLICT - TEAM_ACCESS_DENIED - TEAM_INHERITED_FROM_FOLDER - TEAM_NOT_IN_ORG - THREAD_NOT_FOUND - UNAUTHORIZED - UNSUPPORTED_FILE_TYPE - UPLOAD_FILE_MISMATCH - UPLOAD_INTENT_INVALID - UPLOAD_POLICY_REJECTED - UPSTREAM_UNAVAILABLE - URI_TOO_LONG - WEBSITE_DOMAIN_IMMUTABLE - WEBSITE_DOMAIN_INVALID - WEBSITE_DOMAIN_NOT_CRAWLABLE - WEBSITE_DUPLICATE_DOMAIN - WEBSITE_INVALID_LIST_URL - WEBSITE_NOT_FOUND description: 'A stable refusal code — every refusal the door itself makes carries one, and so does every domain refusal it lets through. The set is additive: a new code is a minor change, so treat a value you do not know as a generic refusal of the status you got.' requestId: type: string description: The response’s `X-Request-Id`, repeated on a 429, on a 500, on a body-size 413 and on a URL-size 414 so a caller can quote it data: type: object properties: retryAfterMs: type: number description: Wait in milliseconds for RATE_LIMITED providers: type: array items: type: string description: For CHAT_MODEL_AMBIGUOUS, the provider slugs that serve the model — name one as `providerSlug` lastMessageId: type: string description: 'For CHAT_TURN_NOT_RUNNING, the newest assistant message on the thread (once it has one) — the idle poll’s own disambiguation: equal to the `messageId` a 202 named means that turn already settled' lastStatus: type: string enum: - pending - complete - failed - cancelled description: For CHAT_TURN_NOT_RUNNING, how `lastMessageId` settled (present with it) organizations: type: array description: For ORG_SLUG_REQUIRED, ORG_SLUG_INVALID and ORG_FORBIDDEN, the organizations the key holder belongs to (a disabled membership is left out; the list is empty when none remains) — send one of the slugs as `X-Organization-Slug` items: type: object required: - slug - name properties: slug: type: string name: type: string issues: type: array description: For INVALID_BODY and INVALID_QUERY, every problem the schema found in the body or the query string; for INVALID_LIMIT and INVALID_CURSOR, the one parameter refused (`limit`, `cursor`); for AUTOMATION_INPUT_INVALID, every problem the automation’s inputs schema found in the run input (at most 20 either way), each naming the field and the reason; `error` repeats the first one items: type: object required: - path - message properties: path: type: string description: The field, dotted for nesting (`address.city`, `contacts.2.email`); empty for a problem with the body as a whole message: type: string scope: type: string enum: - user - team - project - org - apiKey description: 'For BUDGET_EXCEEDED, whose cap is reached: the key holder’s own (`user`), one of their teams’ (`team`), that of the project the work belongs to (`project`), the organization’s (`org`) or this API key’s (`apiKey`)' period: type: string enum: - daily - weekly - monthly description: For BUDGET_EXCEEDED, what the cap counts over — a calendar day, ISO week or calendar month in UTC limitCode: type: string enum: - TOKEN_LIMIT - COST_LIMIT - REQUEST_LIMIT description: 'For BUDGET_EXCEEDED, which cap is reached: tokens, cost in cents, or requests' used: type: number description: For BUDGET_EXCEEDED, the usage the cap measured this period, in its unit (tokens, cents or requests) limit: type: number description: For BUDGET_EXCEEDED, the cap, in the same unit resetsAt: type: number description: For BUDGET_EXCEEDED, when the period resets, in epoch milliseconds — `Retry-After` names the same wait in whole seconds headers: RetryAfter: description: How long to wait before retrying, in whole seconds schema: type: integer minimum: 1 WWWAuthenticate: description: 'The challenge RFC 9110 §11.6.1 requires of a 401: `Bearer`, or `Bearer error="invalid_token"` when a key was presented and refused' schema: type: string XTaleApiVersion: description: The version of this contract (`info.version`) the serving instance implements — semver for the wire schema: type: string example: 3.27.0 ContentDisposition: description: The stored file name as an RFC 6266 attachment (`filename` and `filename*`) schema: type: string ETag: description: 'A validator: over the answer’s bytes on a JSON read, the stored object’s tag on a download. Send it back as `If-None-Match` — as received; the weak and edge-suffixed forms match too — to be told 304 when nothing changed.' schema: type: string ContentLength: description: The byte length of the response body schema: type: integer minimum: 0 Location: description: The created resource’s own path, relative to the request URL — follow it with GET whatever shape the 201 body has schema: type: string Allow: description: The methods this path serves, comma-separated schema: type: string example: GET, POST, HEAD, OPTIONS XRequestId: description: The request id the platform logged this call under — quote it when reporting a problem. Echoes a sane `X-Request-Id` the caller sent. schema: type: string CacheControl: description: '`private, no-cache` on a validated read and on a download: keep the answer, revalidate it before reuse, and let no shared cache keep it. Every other answer says `no-store`.' schema: type: string LastModified: description: When the stored object was last written (HTTP date) schema: type: string securitySchemes: bearerAuth: type: http scheme: bearer description: An organization API key. Create one in Settings → API. Pasted into the explorer on /docs it stays in the page’s memory only and is forgotten on reload — it is never stored.