openapi: 3.2.0 info: title: Tale Platform Documents 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: Documents description: Documents in the knowledge base. paths: /api/v1/documents: get: tags: - Documents summary: List documents description: Knowledge-hub documents the key holder can see, newest first — project files never appear here (the Projects family owns them). `content` is not carried in the listing; read one document for its inline text, or `GET /api/v1/documents/{id}/content` for the bytes. operationId: listDocuments 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: cursor in: query required: false schema: type: string description: The previous page’s `continueCursor`, unchanged — opaque; omit for the first page. A value this list did not answer is refused with 400 `INVALID_CURSOR` rather than read as the first page - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 25 description: Page size, 1..100 (default 25; out-of-range numbers are clamped, a value that is not a number answers 400 `INVALID_LIMIT`) - name: sourceProvider in: query required: false schema: type: string description: Only documents from this source - name: folderId in: query required: false schema: type: string description: Only documents inside this folder — a folder id, or `root` for the documents in no folder. Omit it to list the whole hub, whatever folder a document sits in. - 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: Paginated documents content: application/json: schema: type: object x-tale-pagination: keyset required: - page - isDone - continueCursor properties: page: type: array items: $ref: '#/components/schemas/Document' isDone: type: boolean continueCursor: type: string description: Pass back as `cursor` for the next page; empty when `isDone` 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' post: tags: - Documents summary: Create document description: 'Requires a documents-write role. Send inline `content` from a REST client. Inline content is stored and readable but NOT indexed for knowledge search — only a document backed by an uploaded file (`fileId`) enters the search corpus, and `retry-indexing` answers `skipped` (`content-only`) for the rest. `fileId` must be the key holder’s own unbound upload in this organization. Missing uploads, another user’s uploads and files already bound to a document, thread or conversation answer 404 FILE_NOT_FOUND. REST does not mint hub uploads; use the app to upload first. To put TEXT into the search corpus from REST, create a knowledge entry instead: `POST /api/v1/knowledge-entries` mints a file-backed, indexed Hub document (`sourceProvider: knowledge`, at most 8,000 characters, one active entry per topic). Every file-backed document answers its `indexing` state, so poll it after a create or a `retry-indexing`. The body may run to 32 MiB — this operation’s own cap, sized for the 5,000,000-character inline `content`; past it the answer is 413 `BODY_TOO_LARGE`.' operationId: createDocument security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DocumentInput' responses: '201': description: Created — the new document’s id content: application/json: schema: type: object required: - id properties: id: type: string headers: Location: $ref: '#/components/headers/Location' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '400': description: A body the schema refuses (`INVALID_BODY`); `teamIds` names a team that is not this organization’s (`TEAM_NOT_IN_ORG`, the ids in `data.teamIds`); or `folderId` is a team folder and `teamIds` names a team outside its audience (`TEAM_INHERITED_FROM_FOLDER`) — inside a team folder the folder’s audience applies 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: The key holder’s role cannot write documents, `teamIds` (or `teamId`) names a team a non-admin key holder is not in (`TEAM_ACCESS_DENIED`), or `folderId` names a Hub folder shared with a team the key holder is not in (`FOLDER_NOT_ACCESSIBLE`); 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: The upload is absent, not owned by the key holder or already bound; 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' '413': description: The body exceeds 32 MiB — this operation’s own cap, above the door’s 1 MiB default, sized for a 5,000,000-character inline `content` (`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' '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/documents/{id}: get: tags: - Documents summary: Get document description: A document’s metadata, its `indexing` state and — for a content-only document — its inline `content`; `content` is null for a file-backed document, whose bytes are at `GET /api/v1/documents/{id}/content`. A project file, a foreign document and a nonexistent id all answer the same opaque 404 (`DOCUMENT_NOT_FOUND`). operationId: getDocument 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: id in: path required: true schema: type: string description: Document ID - 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 document content: application/json: schema: $ref: '#/components/schemas/Document' 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: Document not found (`DOCUMENT_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' patch: tags: - Documents summary: Update document description: Partial update; a `null` clears an optional field. Requires a documents-write role. Only Knowledge Hub documents are accepted; project files return 404. A controlled record under review, approval or legal hold refuses the change. Send `expectedUpdatedAt` — the `updatedAt` last read — to refuse a write over a concurrent edit. Answers 200 with the document as it now stands, so the next write has its `updatedAt`. `metadata` MERGES per RFC 7396 — sent keys are set, omitted keys stay, a key sent as `null` is removed, the whole field sent as `null` clears it. A patch that changes nothing — an empty body, or every field already at its value — writes nothing and leaves `updatedAt` alone, so it never spends another client’s `expectedUpdatedAt`. A document that backs an active knowledge entry keeps its title, content, MIME type and extension through the entry (update the entry instead); a folder, team or metadata change goes through. The body may run to 32 MiB — this operation’s own cap, sized for the 5,000,000-character inline `content`; past it the answer is 413 `BODY_TOO_LARGE`. operationId: updateDocument 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: id in: path required: true schema: type: string description: Document ID - name: If-Match in: header required: false schema: type: string description: 'The `ETag` you last read from `GET /api/v1/documents/{id}` — strong comparison, so a `W/` tag never matches — or `*`: the update applies only while the document’s current representation still carries that tag; otherwise 412 `PRECONDITION_FAILED`, `data.etag` naming the current tag, nothing written. The tag covers the whole read, `indexing` included, so a document mid-index answers 412 until it settles; `expectedUpdatedAt` in the body remains the row-level precondition (409 `DOCUMENT_STALE`). Absent, the header is not evaluated.' - 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: $ref: '#/components/schemas/DocumentPatch' responses: '200': description: The document as it now stands — the shape `GET` answers, `updatedAt` included — with the `ETag` of that representation, the value the next `If-Match` sends content: application/json: schema: $ref: '#/components/schemas/Document' headers: ETag: $ref: '#/components/headers/ETag' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '400': description: Invalid request (malformed body or parameters); `teamIds` names a team that is not this organization’s (`TEAM_NOT_IN_ORG`); the document sits in (or moves into) a team folder and `teamIds` names a team outside its audience (`TEAM_INHERITED_FROM_FOLDER`); or the patch touches the content, MIME type, extension or source provider of a controlled record — frozen while in review or approved (`DOCUMENT_RECORD_FROZEN`, `data.state`), or a draft whose bytes move only through the attested replacement flow (`DOCUMENT_RECORD_REPLACEMENT_REQUIRED`) 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: The key holder’s role cannot write documents, `teamIds` (or `teamId`) names a team a non-admin key holder is not in (`TEAM_ACCESS_DENIED`), or `folderId` names a Hub folder shared with a team the key holder is not in (`FOLDER_NOT_ACCESSIBLE`); 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: Document not found (`DOCUMENT_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' '409': description: The record is protected (`DOCUMENT_RECORD_PROTECTED`); the document changed since it was read (`DOCUMENT_STALE` — reload and merge); or it backs an active knowledge entry and the change touches its title, content, MIME type or extension (`DOCUMENT_HAS_KNOWLEDGE_ENTRY`, `data.entryId` names the entry to update instead) content: application/json: schema: $ref: '#/components/schemas/Error' headers: X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' '412': description: The `If-Match` tag does not strongly match the document’s current representation (`PRECONDITION_FAILED`, `data.etag` naming the current tag); nothing written — reload, merge, and send the current `ETag` 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 32 MiB — this operation’s own cap, above the door’s 1 MiB default, sized for a 5,000,000-character inline `content` (`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' '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: - Documents summary: Delete document description: Permanent deletion of a Knowledge Hub document; project files return 404. Role gate, controlled-record protection, legal holds, sync stop and the audit row, then the purge. A document that backs an active knowledge entry is refused — delete the entry (`DELETE /api/v1/knowledge-entries/{id}`), which retires every version of its topic and trashes this document. operationId: deleteDocument 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: id in: path required: true schema: type: string description: Document ID - 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: The key holder’s role cannot write documents; 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: Document not found (`DOCUMENT_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' '409': description: A protected record (`DOCUMENT_RECORD_PROTECTED`), a legal hold (`LEGAL_HOLD_ACTIVE`), or a document that backs an active knowledge entry (`DOCUMENT_HAS_KNOWLEDGE_ENTRY`, `data.entryId` names it — delete the entry instead) 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 purge could not remove every dead surface (`PURGE_INCOMPLETE`): the row was kept so the delete can be retried; or 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/documents/{id}/retry-indexing: post: tags: - Documents summary: Retry RAG indexing description: 'Re-queues a Knowledge Hub document’s blob for indexing; a project file answers 404 here — its own door is `POST /api/v1/projects/{id}/files/{documentId}/retry-indexing`, the same core behind it. Requires a documents-write role. The same guards as the app’s Index now: a budget of 10 retries per user per minute (429 `RATE_LIMITED`, `Retry-After` names the wait), and `skipped` — honestly, with the `reason` — for a content-only document (`content-only`: inline text never enters the search corpus, only file-backed documents do), a blob the platform does not track (`untracked-blob`), a file type no extractor can read (`unsupported` — terminal; the document’s `indexing.error` says why), or a fresh index job already queued or running (`in-progress` — poll the document’s `indexing` instead). A file that opted out of indexing when it was uploaded is opted back in by the retry — the explicit request is the opt-in — so it queues and answers `indexing`; it used to answer `skipped` with `rag-opt-out`, a reason no longer given.' operationId: retryDocumentIndexing 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: id in: path required: true schema: type: string description: Document ID - 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: Whether indexing was queued content: application/json: schema: $ref: '#/components/schemas/RetryIndexingResult' 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: The key holder’s role cannot write documents; 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: 'Document not found (`DOCUMENT_NOT_FOUND`) — a project file included: retry it through its project door; 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' /api/v1/documents/{id}/content: get: tags: - Documents summary: Download a document description: 'The bytes of a Knowledge Hub document — what `GET /api/v1/documents/{id}` cannot carry for a file-backed one: an uploaded file, and the document every knowledge entry mints. Streamed in the response itself (**200**, no redirect to follow), with the document’s title in an RFC 6266 `Content-Disposition` (`filename` and `filename*`), the stored `Content-Type`, `Content-Length`, `ETag` and `Last-Modified`; `Range` is honoured (206, or a bodiless 416 for a range the file cannot satisfy) and a HEAD request answers the headers alone — `Content-Length`, `ETag`, `Last-Modified`, `Accept-Ranges` — ignoring `Range`. A content-only document answers its inline text the same way — typed as its `mimeType` (`text/plain` when it has none), UTF-8, `Accept-Ranges: none` — so every Hub document reads back from this one URL, and `If-None-Match` and `If-Modified-Since` are judged against the `ETag` and `Last-Modified` issued on both kinds (a bodiless 304). A project file, a foreign document, a nonexistent id and a file whose bytes the store no longer holds all answer the same opaque 404 (`DOCUMENT_NOT_FOUND`). A store that does not answer is a 503 with `Retry-After`.' operationId: downloadDocument 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: id in: path required: true schema: type: string description: Document ID - name: If-None-Match in: header required: false schema: type: string description: 'The `ETag` a previous answer carried (as received — the compressing edge suffixes the tag of a text file it compressed, and that 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: bytes not modified since answer 304 with no body, judged at the whole-second precision an HTTP date carries. Ignored when `If-None-Match` is present. On a content-only Hub document the date is the document’s own `updatedAt`, which a title or metadata patch moves too — `If-None-Match` follows the bytes alone.' - 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' Accept-Ranges: $ref: '#/components/headers/AcceptRanges' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' content: '*/*': schema: type: string format: binary '206': description: The bytes of a satisfied `Range` on a file-backed document; `Content-Range` names the slice and the file’s size. Ranges are clamped to the file; a `Range` the server cannot read is ignored and the whole file answers 200 headers: Content-Range: $ref: '#/components/headers/ContentRange' Content-Disposition: $ref: '#/components/headers/ContentDisposition' Content-Length: $ref: '#/components/headers/ContentLength' ETag: $ref: '#/components/headers/ETag' Last-Modified: $ref: '#/components/headers/LastModified' Accept-Ranges: $ref: '#/components/headers/AcceptRanges' X-Request-Id: $ref: '#/components/headers/XRequestId' X-Tale-Api-Version: $ref: '#/components/headers/XTaleApiVersion' content: '*/*': 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 `Accept-Ranges` 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: Document not found (`DOCUMENT_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' '416': description: 'The range starts at or past the end of the file: an empty body (`Content-Length: 0`), no envelope, `Content-Range: bytes */` naming the size' headers: Content-Range: $ref: '#/components/headers/ContentRange' Accept-Ranges: $ref: '#/components/headers/AcceptRanges' Content-Length: $ref: '#/components/headers/ContentLength' 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 object store did not serve the file (`OBJECT_STORE_UNAVAILABLE`, with `Retry-After`) or none is configured (`OBJECT_STORE_UNCONFIGURED`); or 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: DocumentInput: type: object additionalProperties: false required: - title properties: title: type: string minLength: 1 maxLength: 512 content: type: string maxLength: 5000000 fileId: type: string maxLength: 2048 description: The metadata ID of the key holder’s own unbound upload in this organization mimeType: type: string maxLength: 255 extension: type: string maxLength: 32 sourceProvider: type: string maxLength: 64 metadata: type: object additionalProperties: true maxProperties: 500 description: Free-form. At most 64 KiB of JSON, 8 levels of nesting and 500 keys in total (every nested object counted); a larger value answers 400 `INVALID_BODY` naming the path. teamIds: type: array items: type: string minLength: 1 maxLength: 128 maxItems: 64 description: 'The audience: teams of this organization the key holder may assign (their own, unless they are an admin — `TEAM_ACCESS_DENIED`; an id that is not the organization’s is `TEAM_NOT_IN_ORG`). Omitted or empty = organization-wide. Inside a team folder the folder’s audience applies; naming a team outside it is `TEAM_INHERITED_FROM_FOLDER`.' teamId: type: string maxLength: 128 description: The single-team spelling of `teamIds` (still accepted) folderId: type: string maxLength: 64 DocumentPatch: type: object additionalProperties: false description: Every field optional; null clears a nullable field. Applies only to Knowledge Hub documents. A patch that changes nothing writes nothing and leaves `updatedAt` alone. properties: expectedUpdatedAt: type: integer minimum: 0 maximum: 8640000000000000 description: The `updatedAt` last read; the update applies only while the document still carries it, else 409 `DOCUMENT_STALE` title: type: string minLength: 1 maxLength: 512 description: Trimmed — a blank title is 400 `INVALID_BODY` content: type: - string - 'null' maxLength: 5000000 metadata: type: - object - 'null' additionalProperties: true maxProperties: 500 description: Free-form. On PATCH it MERGES per RFC 7396 — sent keys are set, omitted keys stay, a key sent as `null` is removed, and the whole field sent as `null` clears it. At most 64 KiB of JSON, 8 levels of nesting and 500 keys in total (every nested object counted); a larger value answers 400 `INVALID_BODY` naming the path. mimeType: type: - string - 'null' maxLength: 255 extension: type: - string - 'null' maxLength: 32 sourceProvider: type: - string - 'null' maxLength: 64 teamIds: type: array items: type: string minLength: 1 maxLength: 128 maxItems: 64 description: The audience, replaced whole (`[]` = organization-wide); the same rules as on create — inside a team folder the folder’s audience applies (`TEAM_INHERITED_FROM_FOLDER`) teamId: type: - string - 'null' maxLength: 128 description: The single-team spelling of `teamIds`; `null` clears folderId: type: - string - 'null' maxLength: 64 Document: type: object required: - id - title - contentHash - createdBy - createdAt - updatedAt properties: id: type: string title: type: string content: type: - string - 'null' description: Inline text; null for a file-backed document — read its bytes at `GET /api/v1/documents/{id}/content` — and in listings fileId: type: - string - 'null' description: The blob reference mimeType: type: - string - 'null' extension: type: - string - 'null' sourceProvider: type: - string - 'null' teamIds: type: array items: type: string description: 'The audience: the teams that may read the document, by id; empty = organization-wide. Owners and admins read every team library regardless.' teamId: type: - string - 'null' deprecated: true description: The first team of `teamIds`, or null — the pre-1.17.0 single-team spelling; read `teamIds` folderId: type: - string - 'null' metadata: type: - object - 'null' additionalProperties: true contentHash: type: - string - 'null' description: SHA-256 (hex) of the stored bytes when the platform computed one — a knowledge entry’s content, a synced file; null otherwise. A column of its own, never a key in `metadata` createdBy: type: string createdAt: type: integer minimum: 0 description: Epoch milliseconds updatedAt: type: integer minimum: 0 description: Epoch milliseconds indexing: type: object required: - status additionalProperties: false description: Where a file-backed document stands in the search corpus — absent for a content-only document (never indexed) and for a blob the platform does not track. Poll it after a create or a `retry-indexing`. properties: status: type: string enum: - pending - queued - running - completed - failed - unsupported - skipped description: '`pending` — never queued; `skipped` — the file opts out of indexing; `unsupported` — TERMINAL: the platform cannot index these bytes and a retry reproduces the answer, `errorCode` says why (`unsupported_type`, `image_no_vision`, `empty`, `not_text`, `malformed`); `failed` — see `error` / `errorCode`: the job retries `embedding_upstream`, `indexer_error` and `index_rebuilding` by itself, `usage_limit` resumes by itself once the usage limit allows it, the rest wait for an admin (a provider account, the organization’s policy) and a `retry-indexing`; a `failed` with no `errorCode` is a failure the platform settled without classifying it, usually an indexing run that stopped before it finished (a lost job, a stopped worker) — request a `retry-indexing` rather than wait for one' indexedAt: type: integer minimum: 0 description: Epoch ms of the last completed indexing error: type: string description: A sentence for a person, present with `failed` and `unsupported`; never a storage-engine diagnostic — the raw cause stays in the platform log. errorCode: type: string enum: - unsupported_type - image_no_vision - empty - not_text - malformed - secret_detected - pii_blocked - embedding_not_configured - embedding_provider_refused - embedding_upstream - index_rebuilding - index_repair_failed - usage_limit - indexer_error description: 'The stable cause to branch on, present with `unsupported`, and with `failed` whenever the platform classified the cause — a `failed` without one was settled unclassified, usually after its indexing run stopped before it finished; request a `retry-indexing` for it. Terminal (`unsupported`): `unsupported_type` — no extractor for the type; `image_no_vision` — an image and no OCR lane; `empty` — no text to index; `not_text` — binary bytes behind a text extension, re-export as UTF-8; `malformed` — the bytes do not parse as the format the extension claims. Retried by the job (`failed`): `embedding_upstream` — the provider was unreachable, rate-limited or 5xx; `indexer_error` — a platform-side store fault; `index_rebuilding` — the search index is being rebuilt. Waits for a usage limit (`failed`): `usage_limit` — a limit that binds whoever the file is indexed for (its uploader, a synced drive’s owner, the organization for an emailed attachment) has too little room for its embeddings; indexing resumes by itself within the hour after the limit resets or is raised, after what it already embedded. Waits for an admin (`failed`): `embedding_not_configured`, `embedding_provider_refused` (the provider refused the account or credential, the model answers vectors of another width than the settings state, or the platform cannot use the embedding credential — none configured, deleted, disabled or unreadable), `index_repair_failed`, `secret_detected`, `pii_blocked`. Saving corrected embedding settings, or adding or repairing the credential the embedding model uses, re-queues every document that failed on the embedding model.' RetryIndexingResult: type: object required: - status description: What a retry-indexing request did — the one answer the Hub document door and the project-file door share. properties: status: type: string enum: - indexing - skipped description: '`indexing` — the blob was queued (an opt-out lifted); `skipped` — nothing was queued, `reason` says why' reason: type: string enum: - content-only - untracked-blob - unsupported - in-progress description: 'Why indexing was skipped; absent when `status` is `indexing`. `content-only`: inline text never enters the search corpus (a Hub document without a file — never a project file); `untracked-blob`: the platform does not track the blob; `unsupported`: terminal — the platform cannot index these bytes and a retry reproduces the answer; the row’s `indexing.errorCode` names the cause (`unsupported_type`, `image_no_vision`, `empty`, `not_text`, `malformed`); `in-progress`: a fresh index job is already queued or running — poll `indexing` instead.' 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 ContentLength: description: The byte length of the response body schema: type: integer minimum: 0 ContentRange: description: The satisfied range on a 206 (`bytes -/`); on a 416, `bytes */` names the file’s size schema: type: string AcceptRanges: description: '`bytes` — `Range` requests are honoured' schema: type: string example: bytes 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 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 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 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 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.