@sanity/client
Version:
Client for retrieving, creating and patching data from Sanity.io
9,481 lines • 488 kB
JSON
{
"openapi": "3.0.3",
"info": {
"title": "Sanity Context API",
"description": "Build knowledge bases from your content (file uploads, website crawls, and Sanity datasets), then read, triage, and steer what they produce.",
"version": "2026-05-26"
},
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"description": "A Sanity API token or a user token."
}
},
"schemas": {
"EntryDoc": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"knowledgeBaseId": {
"type": "string",
"minLength": 1,
"description": "The ID (`kb…`) of the knowledge base this document belongs to."
},
"_type": {
"type": "string",
"enum": ["sanity.context.entry"],
"description": "The document type. Always `sanity.context.entry`."
},
"schemaVersion": {
"type": "number",
"description": "The version of the document shape. Currently `2`."
},
"revisionId": {
"type": "string",
"description": "The ID of the build that last wrote this entry's content. An unchanged entry keeps its earlier value across builds."
},
"path": {
"type": "string",
"description": "The entry's slash-delimited path, such as `docs/api/webhooks`. Order entries by `path` to get the knowledge base outline."
},
"title": {
"type": "string",
"description": "The entry title."
},
"sectionTitles": {
"description": "The titles of the sections above the entry, top level first, one for each `path` segment before the last. For `groq/functions/math` it holds the titles of `groq` and `groq/functions`. Absent when the entry was written before section titles were recorded.",
"type": "array",
"items": {
"type": "string"
}
},
"tldr": {
"description": "A summary of the entry. `scope` is what the entry covers, and `excludes` is what it does not cover. `neighbors` lists the paths of related entries. `centrality` is how important the entry is: `core`, `standard`, or `peripheral`.",
"type": "object",
"properties": {
"scope": {
"type": "string"
},
"excludes": {
"type": "string"
},
"neighbors": {
"type": "array",
"items": {
"type": "string"
}
},
"centrality": {
"type": "string",
"enum": ["core", "standard", "peripheral"]
}
},
"required": ["scope", "excludes", "centrality"]
},
"body": {
"description": "The entry content in Markdown, with inline `[^key]` footnote markers. The text after `^` in each marker is the `_key` of one item in `citations`. Absent when the entry has no content of its own, such as a `virtual` entry.",
"type": "string"
},
"topicHeadings": {
"description": "The H2 and H3 heading titles in `body`. Absent when the entry has no `body`.",
"type": "array",
"items": {
"type": "string"
}
},
"citations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"pattern": "^[a-z2-7]{10}$",
"description": "Stable ID of this citation: 10 lowercase letters and digits. An entry body points to it with a `[^key]` marker."
},
"_type": {
"type": "string",
"enum": ["sanity.context.citation"]
},
"sourceId": {
"type": "string",
"description": "ID of the source document the quote comes from."
},
"title": {
"type": "string",
"description": "The source's name when it was quoted."
},
"url": {
"description": "Where the source lives on the web. Absent for uploaded files and datasets.",
"type": "string"
},
"quote": {
"type": "string",
"minLength": 1,
"maxLength": 300,
"description": "The passage from the source that backs the claims, copied word for word."
},
"prefix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just before the quote, to tell repeats apart."
},
"suffix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just after the quote, to tell repeats apart."
},
"lineStart": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "First line of the quote, counting from 1. Line numbers match `GET .../sources/{sourceId}/content`. A hint: the quote is the stable locator."
},
"lineEnd": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Last line of the quote, inclusive."
},
"claims": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"description": "The statements in the entry body that this passage backs."
}
},
"required": [
"_key",
"_type",
"sourceId",
"title",
"quote",
"prefix",
"suffix",
"lineStart",
"lineEnd",
"claims"
]
},
"description": "The passages that back this entry, one item per quoted passage, in the order the body first uses them. A source cited twice with different quotes has two items. Empty when the entry has no `body` or the body cites nothing."
},
"sourceIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "The IDs of every source attached to this entry, cited or not, sorted. Every citation `sourceId` is in this list."
},
"status": {
"type": "string",
"enum": ["virtual", "outlined", "filled", "stale", "generation_failed"],
"description": "The entry state. Builds currently write only two values: `virtual` for an entry that groups child entries and has no `body`, and `filled` for an entry with a written `body`. The other values are reserved."
},
"generatedAt": {
"type": "string",
"description": "When the build that last wrote this entry's content ran, as an ISO 8601 timestamp."
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"knowledgeBaseId",
"_type",
"schemaVersion",
"revisionId",
"path",
"title",
"citations",
"sourceIds",
"status",
"generatedAt"
],
"description": "A `sanity.context.entry` document: one entry in a knowledge base outline, stored in your organization's document store. No endpoint returns this document. Use this schema to type GROQ query results."
},
"InstructionDoc": {
"oneOf": [
{
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"knowledgeBaseId": {
"type": "string",
"minLength": 1,
"description": "The ID (`kb…`) of the knowledge base this document belongs to."
},
"_type": {
"type": "string",
"enum": ["sanity.context.instruction"],
"description": "The document type. Always `sanity.context.instruction`."
},
"schemaVersion": {
"type": "number",
"enum": [1],
"description": "The version of the document shape. Currently `1`. An instruction without the current version doesn't appear in lists and doesn't affect builds."
},
"statement": {
"type": "string",
"minLength": 1,
"description": "The instruction, in plain language. Builds follow it over the raw sources."
},
"scopeSources": {
"nullable": true,
"description": "The sources the instruction is tied to. The instruction affects the entries that cite these sources. The API always sets at least one source. When `null`, the instruction isn't tied to any source and doesn't affect builds.",
"minItems": 1,
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"minLength": 1,
"description": "A unique key for this item in the array. It matches `sourceId`."
},
"sourceId": {
"type": "string",
"minLength": 1,
"description": "The ID of the source the instruction is tied to."
},
"contentHash": {
"type": "string",
"minLength": 1,
"description": "The source's content hash when the instruction was last checked against it. When the source content changes, the instruction is checked again."
}
},
"required": ["_key", "sourceId", "contentHash"]
}
},
"status": {
"type": "string",
"enum": ["active", "archived"],
"description": "The instruction state. `active` instructions apply to every build. `archived` instructions don't apply: a source changed and no longer supports the instruction. Editing an archived instruction makes it `active` again."
},
"archivedAt": {
"nullable": true,
"description": "When the instruction was archived, as an ISO 8601 timestamp. `null` while `active`.",
"type": "string"
},
"archivedReason": {
"nullable": true,
"description": "Why the instruction was archived. `null` while `active`.",
"type": "string"
},
"origin": {
"type": "string",
"enum": ["conflict"],
"description": "Where the instruction came from. `conflict` means it was created when you resolved a conflict issue."
},
"sourceIssueId": {
"type": "string",
"minLength": 1,
"description": "The `_id` of the conflict issue this instruction resolved. Reopening that issue deletes this instruction."
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"knowledgeBaseId",
"_type",
"schemaVersion",
"statement",
"scopeSources",
"status",
"archivedAt",
"archivedReason",
"origin",
"sourceIssueId"
]
},
{
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"knowledgeBaseId": {
"type": "string",
"minLength": 1,
"description": "The ID (`kb…`) of the knowledge base this document belongs to."
},
"_type": {
"type": "string",
"enum": ["sanity.context.instruction"],
"description": "The document type. Always `sanity.context.instruction`."
},
"schemaVersion": {
"type": "number",
"enum": [1],
"description": "The version of the document shape. Currently `1`. An instruction without the current version doesn't appear in lists and doesn't affect builds."
},
"statement": {
"type": "string",
"minLength": 1,
"description": "The instruction, in plain language. Builds follow it over the raw sources."
},
"scopeSources": {
"nullable": true,
"description": "The sources the instruction is tied to. The instruction affects the entries that cite these sources. The API always sets at least one source. When `null`, the instruction isn't tied to any source and doesn't affect builds.",
"minItems": 1,
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"minLength": 1,
"description": "A unique key for this item in the array. It matches `sourceId`."
},
"sourceId": {
"type": "string",
"minLength": 1,
"description": "The ID of the source the instruction is tied to."
},
"contentHash": {
"type": "string",
"minLength": 1,
"description": "The source's content hash when the instruction was last checked against it. When the source content changes, the instruction is checked again."
}
},
"required": ["_key", "sourceId", "contentHash"]
}
},
"status": {
"type": "string",
"enum": ["active", "archived"],
"description": "The instruction state. `active` instructions apply to every build. `archived` instructions don't apply: a source changed and no longer supports the instruction. Editing an archived instruction makes it `active` again."
},
"archivedAt": {
"nullable": true,
"description": "When the instruction was archived, as an ISO 8601 timestamp. `null` while `active`.",
"type": "string"
},
"archivedReason": {
"nullable": true,
"description": "Why the instruction was archived. `null` while `active`.",
"type": "string"
},
"origin": {
"type": "string",
"enum": ["human"],
"description": "Where the instruction came from. `human` means it was created directly through the API or the dashboard."
},
"sourceIssueId": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "Always `null` for a `human` instruction."
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"knowledgeBaseId",
"_type",
"schemaVersion",
"statement",
"scopeSources",
"status",
"archivedAt",
"archivedReason",
"origin",
"sourceIssueId"
]
}
],
"description": "A `sanity.context.instruction` document: a standing instruction that steers every build, stored in your organization's document store. No endpoint returns this document. Use this schema to type GROQ query results. To change instructions, use the instructions endpoints."
},
"IssueDoc": {
"oneOf": [
{
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"knowledgeBaseId": {
"type": "string",
"minLength": 1,
"description": "The ID (`kb…`) of the knowledge base this document belongs to."
},
"_type": {
"type": "string",
"enum": ["sanity.context.issue"],
"description": "The document type. Always `sanity.context.issue`."
},
"schemaVersion": {
"type": "number",
"enum": [1],
"description": "The version of the document shape. Currently `1`."
},
"content": {
"oneOf": [
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["conflict"],
"description": "The issue type. `conflict` means two or more positions disagree on the same fact, and you choose which one is correct."
},
"claimKey": {
"type": "string",
"description": "A key naming the disputed fact, such as `free_tier.request_limit`. It never includes the disputed value, so every side shares it."
},
"context": {
"description": "One sentence that explains the question, when it needs one.",
"type": "string"
},
"sides": {
"minItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"claim": {
"type": "string",
"description": "The position as a self-contained sentence. This is the option you choose from."
},
"value": {
"description": "The disputed value on its own, such as `10,000/month`, without the sentence.",
"type": "string"
},
"entryPaths": {
"description": "Paths of the entries that state this position.",
"type": "array",
"items": {
"type": "string"
}
},
"sourceIds": {
"description": "IDs of the sources that directly back this position.",
"type": "array",
"items": {
"type": "string"
}
},
"where": {
"description": "The documents that state this value, by the names you know them by.",
"type": "string"
},
"citations": {
"description": "Quotes from the documents that state this value, copied word for word and checked against each document. A document whose wording could not be checked has none.",
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"pattern": "^[a-z2-7]{10}$",
"description": "Stable ID of this citation: 10 lowercase letters and digits. An entry body points to it with a `[^key]` marker."
},
"_type": {
"type": "string",
"enum": ["sanity.context.citation"]
},
"sourceId": {
"type": "string",
"description": "ID of the source document the quote comes from."
},
"title": {
"type": "string",
"description": "The source's name when it was quoted."
},
"url": {
"description": "Where the source lives on the web. Absent for uploaded files and datasets.",
"type": "string"
},
"quote": {
"type": "string",
"minLength": 1,
"maxLength": 300,
"description": "The passage from the source that backs the claims, copied word for word."
},
"prefix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just before the quote, to tell repeats apart."
},
"suffix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just after the quote, to tell repeats apart."
},
"lineStart": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "First line of the quote, counting from 1. Line numbers match `GET .../sources/{sourceId}/content`. A hint: the quote is the stable locator."
},
"lineEnd": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Last line of the quote, inclusive."
}
},
"required": [
"_key",
"_type",
"sourceId",
"title",
"quote",
"prefix",
"suffix",
"lineStart",
"lineEnd"
]
}
},
"authority": {
"description": "How much weight the sources behind this position carry. `primary`: your own content, such as uploaded files and pages on your own site. `secondary`: other sources. `community`: forums and Q&A sites.",
"type": "string",
"enum": ["primary", "secondary", "community"]
}
},
"required": ["claim"],
"description": "One position in a conflict, and the entries and sources it comes from."
},
"description": "The conflicting positions, at least two. To resolve the conflict, pass the index of one side as `resolution`."
},
"suggested": {
"description": "Index in `sides` of the suggested side, when there is one. It is only a hint: nothing is chosen until you resolve the issue.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"severity",
"scopePath",
"issue",
"suggestedFix",
"kind",
"claimKey",
"sides"
],
"description": "A conflict: two or more positions disagree on the same fact, and you choose which one is correct."
},
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["update_required"],
"description": "The issue type. `update_required` means an entry is out of date with its sources or contradicts an instruction, and needs a rewrite."
},
"citedSourceIds": {
"description": "IDs of the sources that led to the issue.",
"type": "array",
"items": {
"type": "string"
}
},
"claimKey": {
"description": "A key naming the specific finding, when the check that found it sets one.",
"type": "string"
},
"involvedScopes": {
"description": "Paths of the entries the issue involves, when it spans more than one entry.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["severity", "scopePath", "issue", "suggestedFix", "kind"],
"description": "An entry that needs a rewrite: it is out of date with its sources or contradicts an instruction."
}
],
"description": "What an issue found. The shape depends on `kind`."
},
"fingerprint": {
"type": "string",
"minLength": 1,
"description": "An identity for the finding that doesn't depend on its wording. It determines the issue's `_id`, so a reworded finding updates the same issue."
},
"revisionId": {
"nullable": true,
"description": "The ID of the build that filed this issue. `null` when the issue was filed outside a build, such as when removing a source leaves an entry without sources.",
"type": "string",
"minLength": 1
},
"status": {
"type": "string",
"enum": ["open"],
"description": "The issue status. `open` means it is waiting for triage."
},
"resolution": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "Always `null` while the issue is `open`."
},
"resolvedAt": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "Always `null` while the issue is `open`."
},
"resolvedBy": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "Always `null` while the issue is `open`."
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"knowledgeBaseId",
"_type",
"schemaVersion",
"content",
"fingerprint",
"revisionId",
"status",
"resolution",
"resolvedAt",
"resolvedBy"
]
},
{
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"knowledgeBaseId": {
"type": "string",
"minLength": 1,
"description": "The ID (`kb…`) of the knowledge base this document belongs to."
},
"_type": {
"type": "string",
"enum": ["sanity.context.issue"],
"description": "The document type. Always `sanity.context.issue`."
},
"schemaVersion": {
"type": "number",
"enum": [1],
"description": "The version of the document shape. Currently `1`."
},
"content": {
"oneOf": [
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["conflict"],
"description": "The issue type. `conflict` means two or more positions disagree on the same fact, and you choose which one is correct."
},
"claimKey": {
"type": "string",
"description": "A key naming the disputed fact, such as `free_tier.request_limit`. It never includes the disputed value, so every side shares it."
},
"context": {
"description": "One sentence that explains the question, when it needs one.",
"type": "string"
},
"sides": {
"minItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"claim": {
"type": "string",
"description": "The position as a self-contained sentence. This is the option you choose from."
},
"value": {
"description": "The disputed value on its own, such as `10,000/month`, without the sentence.",
"type": "string"
},
"entryPaths": {
"description": "Paths of the entries that state this position.",
"type": "array",
"items": {
"type": "string"
}
},
"sourceIds": {
"description": "IDs of the sources that directly back this position.",
"type": "array",
"items": {
"type": "string"
}
},
"where": {
"description": "The documents that state this value, by the names you know them by.",
"type": "string"
},
"citations": {
"description": "Quotes from the documents that state this value, copied word for word and checked against each document. A document whose wording could not be checked has none.",
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"pattern": "^[a-z2-7]{10}$",
"description": "Stable ID of this citation: 10 lowercase letters and digits. An entry body points to it with a `[^key]` marker."
},
"_type": {
"type": "string",
"enum": ["sanity.context.citation"]
},
"sourceId": {
"type": "string",
"description": "ID of the source document the quote comes from."
},
"title": {
"type": "string",
"description": "The source's name when it was quoted."
},
"url": {
"description": "Where the source lives on the web. Absent for uploaded files and datasets.",
"type": "string"
},
"quote": {
"type": "string",
"minLength": 1,
"maxLength": 300,
"description": "The passage from the source that backs the claims, copied word for word."
},
"prefix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just before the quote, to tell repeats apart."
},
"suffix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just after the quote, to tell repeats apart."
},
"lineStart": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "First line of the quote, counting from 1. Line numbers match `GET .../sources/{sourceId}/content`. A hint: the quote is the stable locator."
},
"lineEnd": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Last line of the quote, inclusive."
}
},
"required": [
"_key",
"_type",
"sourceId",
"title",
"quote",
"prefix",
"suffix",
"lineStart",
"lineEnd"
]
}
},
"authority": {
"description": "How much weight the sources behind this position carry. `primary`: your own content, such as uploaded files and pages on your own site. `secondary`: other sources. `community`: forums and Q&A sites.",
"type": "string",
"enum": ["primary", "secondary", "community"]
}
},
"required": ["claim"],
"description": "One position in a conflict, and the entries and sources it comes from."
},
"description": "The conflicting positions, at least two. To resolve the conflict, pass the index of one side as `resolution`."
},
"suggested": {
"description": "Index in `sides` of the suggested side, when there is one. It is only a hint: nothing is chosen until you resolve the issue.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"severity",
"scopePath",
"issue",
"suggestedFix",
"kind",
"claimKey",
"sides"
],
"description": "A conflict: two or more positions disagree on the same fact, and you choose which one is correct."
},
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["update_required"],
"description": "The issue type. `update_required` means an entry is out of date with its sources or contradicts an instruction, and needs a rewrite."
},
"citedSourceIds": {
"description": "IDs of the sources that led to the issue.",
"type": "array",
"items": {
"type": "string"
}
},
"claimKey": {
"description": "A key naming the specific finding, when the check that found it sets one.",
"type": "string"
},
"involvedScopes": {
"description": "Paths of the entries the issue involves, when it spans more than one entry.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["severity", "scopePath", "issue", "suggestedFix", "kind"],
"description": "An entry that needs a rewrite: it is out of date with its sources or contradicts an instruction."
}
],
"description": "What an issue found. The shape depends on `kind`."
},
"fingerprint": {
"type": "string",
"minLength": 1,
"description": "An identity for the finding that doesn't depend on its wording. It determines the issue's `_id`, so a reworded finding updates the same issue."
},
"revisionId": {
"nullable": true,
"description": "The ID of the build that filed this issue. `null` when the issue was filed outside a build, such as when removing a source leaves an entry without sources.",
"type": "string",
"minLength": 1
},
"status": {
"type": "string",
"enum": ["accepted"],
"description": "The issue status. `accepted` means the issue was resolved or its fix applied."
},
"resolvedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the issue left `open`, as an ISO 8601 timestamp."
},
"resolvedBy": {
"nullable": true,
"description": "Who triaged the issue. `null` while the issue is open, or when the caller could not be identified.",
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "The ID of the Sanity user or robot token that triaged the issue."
},
"kind": {
"type": "string",
"enum": ["user", "robot"],
"description": "What triaged the issue. `user` is a person, and `robot` is a robot token."
}
},
"required": ["id", "kind"]
},
"resolution": {
"nullable": true,
"description": "The index of the chosen side in `content.sides`. For a conflict on one entry, index `0` is the entry's own position. `null` when the fix was applied without choosing a side.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"knowledgeBaseId",
"_type",
"schemaVersion",
"content",
"fingerprint",
"revisionId",
"status",
"resolvedAt",
"resolvedBy",
"resolution"
]
},
{
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"knowledgeBaseId": {
"type": "string",
"minLength": 1,
"description": "The ID (`kb…`) of the knowledge base this document belongs to."
},
"_type": {
"type": "string",
"enum": ["sanity.context.issue"],
"description": "The document type. Always `sanity.context.issue`."
},
"schemaVersion": {
"type": "number",
"enum": [1],
"description": "The version of the document shape. Currently `1`."
},
"content": {
"oneOf": [
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["conflict"],
"description": "The issue type. `conflict` means two or more positions disagree on the same fact, and you choose which one is correct."
},
"claimKey": {
"type": "string",
"description": "A key naming the disputed fact, such as `free_tier.request_limit`. It never includes the disputed value, so every side shares it."
},
"context": {
"description": "One sentence that explains the question, when it needs one.",
"type": "string"
},
"sides": {
"minItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"claim": {
"type": "string",
"description": "The position as a self-contained sentence. This is the option you choose from."
},
"value": {
"description": "The disputed value on its own, such as `10,000/month`, without the sentence.",
"type": "string"
},
"entryPaths": {
"description": "Paths of the entries that state this position.",
"type": "array",
"items": {
"type": "string"
}
},
"sourceIds": {
"description": "IDs of the sources that directly back this position.",
"type": "array",
"items": {
"type": "string"
}
},
"where": {
"description": "The documents that state this value, by the names you know them by.",
"type": "string"
},
"citations": {
"description": "Quotes from the documents that state this value, copied word for word and checked against each document. A document whose wording could not be checked has none.",
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"pattern": "^[a-z2-7]{10}$",
"description": "Stable ID of this citation: 10 lowercase letters and digits. An entry body points to it with a `[^key]` marker."
},
"_type": {
"type": "string",
"enum": ["sanity.context.citation"]
},
"sourceId": {
"type": "string",
"description": "ID of the source document the quote comes from."
},
"title": {
"type": "string",
"description": "The source's name when it was quoted."
},
"url": {
"description": "Where the source lives on the web. Absent for uploaded files and datasets.",
"type": "string"
},
"quote": {
"type": "string",
"minLength": 1,
"maxLength": 300,
"description": "The passage from the source that backs the claims, copied word for word."
},
"prefix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just before the quote, to tell repeats apart."
},
"suffix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just after the quote, to tell repeats apart."
},
"lineStart": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "First line of the quote, counting from 1. Line numbers match `GET .../sources/{sourceId}/content`. A hint: the quote is the stable locator."
},
"lineEnd": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Last line of the quote, inclusive."
}
},
"required": [
"_key",
"_type",
"sourceId",
"title",
"quote",
"prefix",
"suffix",
"lineStart",
"lineEnd"
]
}
},
"authority": {
"description": "How much weight the sources behind this position carry. `primary`: your own content, such as uploaded files and pages on your own site. `secondary`: other sources. `community`: forums and Q&A sites.",
"type": "string",
"enum": ["primary", "secondary", "community"]
}
},
"required": ["claim"],
"description": "One position in a conflict, and the entries and sources it comes from."
},
"description": "The conflicting positions, at least two. To resolve the conflict, pass the index of one side as `resolution`."
},
"suggested": {
"description": "Index in `sides` of the suggested side, when there is one. It is only a hint: nothing is chosen until you resolve the issue.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"severity",
"scopePath",
"issue",
"suggestedFix",
"kind",
"claimKey",
"sides"
],
"description": "A conflict: two or more positions disagree on the same fact, and you choose which one is correct."
},
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["update_required"],
"description": "The issue type. `update_required` means an entry is out of date with its sources or contradicts an instruction, and needs a rewrite."
},
"citedSourceIds": {
"description": "IDs of the sources that led to the issue.",
"type": "array",
"items": {
"type": "string"
}
},
"claimKey": {
"description": "A key naming the specific finding, when the check that found it sets one.",
"type": "string"
},
"involvedScopes": {
"description": "Paths of the entries the issue involves, when it spans more than one entry.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["severity", "scopePath", "issue", "suggestedFix", "kind"],
"description": "An entry that needs a rewrite: it is out of date with its sources or contradicts an instruction."
}
],
"description": "What an issue found. The shape depends on `kind`."
},
"fingerprint": {
"type": "string",
"minLength": 1,
"description": "An identity for the finding that doesn't depend on its wording. It determines the issue's `_id`, so a reworded finding updates the same issue."
},
"revisionId": {
"nullable": true,
"description": "The ID of the build that filed this issue. `null` when the issue was filed outside a build, such as when removing a source leaves an entry without sources.",
"type": "string",
"minLength": 1
},
"status": {
"type": "string",
"enum": ["rejected"],
"description": "The issue status. `rejected` means the issue was dismissed. Dismissal is final."
},
"resolvedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the issue left `open`, as an ISO 8601 timestamp."
},
"resolvedBy": {
"nullable": true,
"description": "Who triaged the issue. `null` while the issue is open, or when the caller could not be identified.",
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "The ID of the Sanity user or robot token that triaged the issue."
},
"kind": {
"type": "string",
"enum": ["user", "robot"],
"description": "What triaged the issue. `user` is a person, and `robot` is a robot token."
}
},
"required": ["id", "kind"]
},
"resolution": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "Always `null`, because a dismissal chooses no side."
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"knowledgeBaseId",
"_type",
"schemaVersion",
"content",
"fingerprint",
"revisionId",
"status",
"resolvedAt",
"resolvedBy",
"resolution"
]
}
],
"description": "A `sanity.context.issue` document: a build finding waiting for triage, stored in your organization's document store. No endpoint returns this document. Use this schema to type GROQ query results and Sanity Function filters. To change an issue's status, use the issues endpoints. Only a `conflict` issue can have a non-null `resolution`."
},
"ConversationDoc": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"_type": {
"type": "string",
"enum": ["sanity.context.conversation"],
"description": "The document type. Always `sanity.context.conversation`."
},
"schemaVersion": {
"type": "number",
"enum": [1],
"description": "The version of the document shape. Currently `1`."
},
"organizationId": {
"type": "string",
"minLength": 1,
"description": "The ID of the organization that owns the conversation. Filter on it in every query, because the document store also holds documents from other features."
},
"threadId": {
"type": "string",
"minLength": 1,
"description": "Your identifier for the conversation thread, unique within the organization. It is the `threadId` in the conversations endpoint path and determines the document `_id`."
},
"metadata": {
"nullable": true,
"description": "Tags that describe the conversation, such as `mcpEndpoints`, `app`, and `environment`. Filter on them in GROQ queries. `null` until a save includes `metadata`.",
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 256
},
{
"maxItems": 20,
"type": "array",
"items": {
"type": "string",
"maxLength": 256
}
}
]
}
},
"startedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the API received the first save for this thread, as an ISO 8601 timestamp."
},
"messagesUpdatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the conversation was last saved, as an ISO 8601 timestamp."
},
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"role": {
"type": "string",
"enum": ["user", "assistant", "system", "tool"],
"description": "Who sent the message. `user` is the person talking to the agent, `assistant` is the agent, `system` is a system prompt, and `tool` is a tool call or tool result."
},
"content": {
"default": null,
"description": "The message text. `null` when the message has no text, such as a tool call.",
"nullable": true,
"type": "string",
"maxLength": 20000
},
"toolName": {
"default": null,
"description": "The name of the tool for a `tool` message. `null` on other messages.",
"nullable": true,
"type": "string"
},
"toolType": {
"default": null,
"description": "The kind of `tool` message. `call` is the agent calling the tool, and `result` is what the tool returned. `null` on other messages.",
"nullable": true,
"type": "string",
"enum": ["call", "result", null]
},
"error": {
"default": null,
"description": "Why this step failed, including any stack trace. Set it on the tool result for a failed tool call, or on the assistant message for a turn that failed instead of answering. `null` when the step succeeded.",
"nullable": true,
"type": "string",
"maxLength": 20000
},
"timestamp": {
"default": null,
"description": "When the API first received this message, as an ISO 8601 timestamp. The API sets it. Resending an unchanged message at the same position keeps its timestamp. `null` for messages recorded before timestamps existed.",
"nullable": true,
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": ["role", "content", "toolName", "toolType", "error", "timestamp"],
"description": "One message in a conversation transcript, with the time the API received it."
},
"description": "The conversation transcript, in order. Each save replaces it."
},
"modelProvider": {
"nullable": true,
"description": "The provider of the model the agent used. `null` until a save includes `modelProvider`.",
"type": "string"
},
"modelId": {
"nullable": true,
"description": "The ID of the model the agent used. `null` until a save includes `modelId`.",
"type": "string"
},
"tokenUsage": {
"nullable": true,
"description": "The running total of token usage for the conversation. `null` until a save includes `tokenUsage`.",
"type": "object",
"properties": {
"inputTokens": {
"description": "The number of input tokens.",
"type": "number"
},
"outputTokens": {
"description": "The number of output tokens.",
"type": "number"
},
"totalTokens": {
"description": "The total number of tokens.",
"type": "number"
}
}
},
"coreMetrics": {
"nullable": true,
"description": "The latest classification result. `null` until you record one.",
"type": "object",
"properties": {
"successScore": {
"description": "How well the agent resolved the user's needs, from 1 to 10.",
"type": "number"
},
"sentiment": {
"description": "The overall sentiment of the conversation.",
"type": "string",
"enum": ["positive", "neutral", "negative"]
},
"contentGaps": {
"description": "Topics the agent couldn't answer because it lacked content.",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"classifiedAt": {
"nullable": true,
"description": "When the latest classification result was recorded, as an ISO 8601 timestamp. The API sets it. `null` until you record a result.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"classificationError": {
"nullable": true,
"description": "Why your classifier couldn't classify the conversation. `null` when no failure is recorded. Recording a result clears it.",
"type": "string"
},
"sharing": {
"default": null,
"description": "Your choice to share conversation telemetry with Sanity. `null` until a save includes `sharing`.",
"nullable": true,
"type": "object",
"properties": {
"metrics": {
"description": "Whether to share classification metrics with Sanity: scores, sentiment, content gap counts, message counts and sizes, tool names, and model and token usage. Message content is not included.",
"type": "boolean"
},
"conversations": {
"description": "Whether to share full conversation transcripts with Sanity. When `true`, the API also sets `metrics` to `true`.",
"type": "boolean"
},
"contact": {
"description": "How the Sanity team can reach you about your agent, such as an email address or a Discord handle.",
"type": "string",
"maxLength": 200
}
}
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"_type",
"schemaVersion",
"organizationId",
"threadId",
"metadata",
"startedAt",
"messagesUpdatedAt",
"messages",
"modelProvider",
"modelId",
"tokenUsage",
"coreMetrics",
"classifiedAt",
"classificationError",
"sharing"
],
"description": "A `sanity.context.conversation` document: one agent conversation and its classification, stored in your organization's document store. No endpoint returns this document. Use this schema to type GROQ query results. To record conversations, use the conversations endpoints."
},
"McpDoc": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"minLength": 1,
"description": "The document ID."
},
"_rev": {
"type": "string",
"minLength": 1,
"description": "The document revision. It changes on every write."
},
"_createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was created, as an ISO 8601 timestamp."
},
"_updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the document was last changed, as an ISO 8601 timestamp."
},
"_type": {
"type": "string",
"enum": ["sanity.context.mcp"],
"description": "The document type. Always `sanity.context.mcp`."
},
"schemaVersion": {
"type": "number",
"enum": [1],
"description": "The version of the document shape. Currently `1`."
},
"organizationId": {
"type": "string",
"minLength": 1,
"description": "The ID of the organization that owns the MCP endpoint. Filter on it in every query, because the document store also holds documents from other features."
},
"publicId": {
"type": "string",
"minLength": 1,
"description": "The MCP endpoint's public ID (`mcp…`). It is set once at creation, never changes, and determines the document `_id`."
},
"title": {
"type": "string",
"minLength": 1,
"description": "The MCP endpoint's display name. You can change it at any time."
},
"name": {
"type": "string",
"minLength": 1,
"description": "The MCP endpoint's name in its URL, in lowercase kebab case such as `my-endpoint`. It is unique within the organization and can't change after creation."
},
"sources": {
"minItems": 1,
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["knowledge-base"],
"description": "The source type. `knowledge-base` serves a whole knowledge base."
},
"id": {
"type": "string",
"minLength": 1,
"description": "The knowledge base ID (`kb…`)."
}
},
"required": ["type", "id"]
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["dataset"],
"description": "The source type. `dataset` serves documents from a Sanity dataset, limited by the MCP endpoint's `groqFilter` when set."
},
"id": {
"type": "string",
"pattern": "^[a-z0-9]+\\.[a-z0-9][a-z0-9_-]*$",
"description": "The dataset, as `<projectId>.<datasetName>`."
},
"workspace": {
"default": null,
"description": "The studio workspace whose schema agents use, by name. `null` uses the studio's first workspace.",
"nullable": true,
"type": "string",
"minLength": 1
},
"perspective": {
"default": null,
"description": "The perspective agents query the dataset with: `published`, `drafts`, or `raw`. `null` uses `published`.",
"nullable": true,
"type": "string",
"enum": ["published", "drafts", "raw", null]
},
"semanticSearch": {
"default": null,
"description": "Whether agents can use semantic search on the dataset. `false` turns it off. `true` or `null` use it while the dataset has embeddings enabled and the organization has embeddings usage left.",
"nullable": true,
"type": "boolean"
}
},
"required": ["type", "id", "workspace", "perspective", "semanticSearch"]
}
],
"description": "A content source that an MCP endpoint serves: a knowledge base or a Sanity dataset."
},
"description": "The content sources the MCP endpoint serves, all at once. Each source appears once, there is at most one `dataset` source, and the order has no meaning."
},
"instructions": {
"nullable": true,
"description": "Prompt text the MCP endpoint serves to connecting agents. `null` when unset.",
"type": "string"
},
"groqFilter": {
"nullable": true,
"description": "A GROQ filter that limits what the MCP endpoint's `dataset` source serves. It has no effect on `knowledge-base` sources. `null` when unset. The API clears it when the endpoint has no `dataset` source.",
"type": "string"
}
},
"required": [
"_id",
"_rev",
"_createdAt",
"_updatedAt",
"_type",
"schemaVersion",
"organizationId",
"publicId",
"title",
"name",
"sources",
"instructions",
"groqFilter"
],
"description": "A `sanity.context.mcp` document: the configuration of one MCP endpoint, stored in your organization's document store. No endpoint returns this document. Use this schema to type GROQ query results and Sanity Function filters. Manage MCP endpoints in the Context dashboard."
},
"ApiErrorBody": {
"type": "object",
"properties": {
"statusCode": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"error": {
"type": "string"
},
"code": {
"type": "string",
"enum": [
"knowledgeBaseNotFound",
"jobNotFound",
"importNotFound",
"sourceNotFound",
"entryNotFound",
"entryDocumentInvalid",
"revisionNotFound",
"revisionNotBrowsable",
"revisionNotRestorable",
"buildDecisionsNotFound",
"issueNotFound",
"instructionNotFound",
"webSourceRootNotFound",
"routeNotFound",
"buildInFlight",
"importInvalidState",
"sourceNotDistilled",
"webSourceRootConflict",
"webSourceRootLimitExceeded",
"uploadTooLarge",
"payloadTooLarge",
"validationError",
"unsupportedMediaType",
"issueNotResolvable",
"issueNotAutoApplicable",
"issueDocumentInvalid",
"issueTransitionConflict",
"refreshControlsUnavailable",
"datasetSourceTooLarge",
"datasetSourceEmpty",
"datasetAlreadyBound",
"datasetSourceNotBound",
"datasetReadAccessDenied",
"invalidGroqFilter",
"mcpEndpointNotFound",
"mcpEndpointNameConflict",
"mcpSourceKnowledgeBaseNotFound",
"mcpEndpointNotServable",
"conversationNotFound",
"missingCredential",
"invalidCredential",
"missingOrganization",
"organizationAccessDenied",
"knowledgeBaseAccessDenied",
"contextGrantRequired",
"knowledgeBaseCreateAccessDenied",
"mcpEndpointManageAccessDenied",
"insightsWriteAccessDenied",
"projectAdminRequired",
"accessCheckFailed",
"planLimitReached",
"featureNotInPlan",
"buildCapReached",
"tooManyConnections",
"jobsUnavailable",
"contextStoreUnavailable",
"crawlingUnavailable",
"crawlPreviewUnavailable",
"instructionDraftFailed",
"instructionScopeVanished",
"idempotencyKeyReused",
"idempotencyRequestInFlight",
"idempotencyParamsMismatch",
"internal"
]
},
"message": {
"type": "string"
},
"fields": {
"type": "object",
"additionalProperties": {}
}
},
"required": ["statusCode", "error", "code", "message"],
"description": "The body of every error response. Branch on `code`, a stable identifier; `message` is human-readable and can change."
}
}
},
"paths": {
"/{apiVersion}/context/knowledge-bases": {
"get": {
"operationId": "listKnowledgeBases",
"summary": "List knowledge bases",
"tags": ["knowledge-bases"],
"description": "Returns the knowledge bases you can access in the organization set by `organizationId`. Results are cursor-paginated, newest first.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "cursor",
"required": false,
"description": "The `nextCursor` value from the previous page. Omit it to get the first page."
},
{
"schema": {
"default": 50,
"type": "integer",
"minimum": 1,
"maximum": 200
},
"in": "query",
"name": "limit",
"required": false,
"description": "The maximum number of items to return."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "query",
"name": "organizationId",
"required": true,
"description": "The organization to list knowledge bases for."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A page of knowledge bases.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "An internal UUID for the knowledge base, still accepted wherever a `knowledgeBaseId` is expected. Use `publicId` instead."
},
"publicId": {
"type": "string",
"description": "The knowledge base's ID, such as `kb3do82whm`. Store this one, and pass it as `knowledgeBaseId` in paths and filters. Treat it as an opaque string."
},
"organizationId": {
"type": "string",
"description": "The ID of the organization that owns the knowledge base."
},
"title": {
"type": "string",
"description": "The knowledge base's title."
},
"description": {
"type": "string",
"description": "A short description of what the knowledge base covers."
},
"state": {
"type": "string",
"enum": ["created", "building", "ready", "review", "stale", "paused"],
"description": "The knowledge base's build state. `created`: not built yet. `ready`: built, with no open issues. `review`: built, with open issues to review. A failed build doesn't change the state. `building`, `stale`, and `paused` aren't currently returned. To check for a running build, use `isBuilding`."
},
"activeJobId": {
"nullable": true,
"description": "The job ID of the most recent build, or `null` if no build has started. Check its progress with `GET .../jobs/{jobId}`.",
"type": "string"
},
"isBuilding": {
"type": "boolean",
"description": "Whether a build is running now."
},
"buildStageState": {
"nullable": true,
"description": "Progress of the most recent build, by stage. `null` until a build reports progress. It can briefly belong to an earlier build, so use it only when its `jobId` matches `activeJobId`.",
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The ID of the build job this progress belongs to."
},
"stages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"tldr",
"map",
"triage",
"plan",
"organize",
"arrange",
"write",
"review",
"polish"
],
"description": "The stage's ID. Which stages a build runs can change between builds and knowledge bases, so handle IDs you don't recognize."
},
"status": {
"type": "string",
"enum": ["pending", "running", "done", "failed"],
"description": "The stage's status. `pending`: not started. `running`: in progress. `done`: finished. `failed`: the build ended before the stage finished."
},
"units": {
"description": "The stage's progress counts. Absent when the stage hasn't reported counts.",
"type": "object",
"properties": {
"unit": {
"type": "string",
"enum": ["sources", "groups", "entries", "rounds"],
"description": "What `done` and `total` count: `sources`, `groups` of related content, `entries`, or `rounds` of final fixes. A `rounds` stage has no `total`."
},
"done": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many units the stage has finished."
},
"total": {
"description": "How many units the stage will process. Absent when `unit` is `rounds`.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": ["unit", "done"]
}
},
"required": ["id", "status"]
},
"description": "The build's stages and their progress. Stages that haven't reported yet can be missing."
}
},
"required": ["jobId", "stages"]
},
"lastCheckedAt": {
"nullable": true,
"description": "When a refresh last checked the knowledge base for changes, whether or not anything changed. `null` until the first refresh.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"lastChangedAt": {
"nullable": true,
"description": "When the content last changed: the time of the most recent successful build. `null` if the knowledge base has never built.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"hasPendingChanges": {
"type": "boolean",
"description": "Whether sources were added, changed, or removed since the last successful build. A change a check already reviewed without filing an issue, or that a dismissed issue covered, no longer counts. Always `false` before the first build."
},
"pendingChanges": {
"nullable": true,
"description": "Counts of sources added, changed, and removed since the last successful build, excluding changes a check already reviewed without filing an issue or that a dismissed issue covered. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it. `null` in list responses and before the first build.",
"type": "object",
"properties": {
"added": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources added since the last successful build, including sources no successful build has included yet."
},
"changed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources whose content changed since the last successful build."
},
"removed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources that recent refreshes no longer find."
}
},
"required": ["added", "changed", "removed"]
},
"pipelineOutdated": {
"type": "boolean",
"description": "Whether Sanity Context has improved how it builds knowledge bases since the last successful build. Rebuild to apply the improvements. Always `false` before the first build."
},
"rebuildRecommended": {
"nullable": true,
"description": "A recommendation to rebuild, because new or changed content doesn't fit the current outline, or pages are out of date with changed sources and only a build updates them. `null` when there's no recommendation. A refresh where the content fits again, a successful build, or adding or removing sources clears it.",
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "Why a rebuild is recommended, written to show to users."
},
"at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the recommendation was made."
}
},
"required": ["reason", "at"]
},
"hasWebSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one website source."
},
"hasDatasetSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one Sanity dataset source."
},
"sourceUsage": {
"nullable": true,
"description": "How many sources the knowledge base uses, and its source limit.",
"type": "object",
"properties": {
"used": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources counted toward the limit, including parts split from large sources."
},
"limit": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The maximum number of sources the knowledge base can have."
}
},
"required": ["used", "limit"]
},
"sourceChunks": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of source chunks the knowledge base holds, in the sources counted by `sourceUsage`, whether or not they have been built. Sources still being processed add theirs once converted."
},
"buildRestriction": {
"nullable": true,
"description": "Why a build request would be denied right now, or `null` if you can build. Only `GET .../knowledge-bases/{knowledgeBaseId}` checks it. List and create responses always return `null`.",
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "A stable code for the restriction, such as `planLimitReached`."
},
"message": {
"type": "string",
"description": "A readable explanation that you can show to users."
}
},
"required": ["code", "message"]
},
"refreshEnabled": {
"type": "boolean",
"description": "Whether scheduled refresh is on. Only applies to knowledge bases with a website or dataset source."
},
"refreshFrequency": {
"type": "string",
"enum": ["weekly", "monthly"],
"description": "How often scheduled refresh runs: `weekly` (the default) or `monthly`."
},
"refreshNextRunAt": {
"nullable": true,
"description": "When the next scheduled refresh runs. `null` when scheduled refresh is off or not scheduled yet. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `null`.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"refreshInFlight": {
"type": "boolean",
"description": "Whether a refresh is running now. While it's `true`, a new refresh request doesn't start another one. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `false`."
},
"openIssueCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of open issues waiting for review. Always `0` before the first build."
},
"instructionCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of active instructions for the knowledge base."
},
"createdBy": {
"nullable": true,
"description": "Who created the knowledge base. `null` if unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was last updated."
}
},
"required": [
"id",
"publicId",
"organizationId",
"title",
"description",
"state",
"activeJobId",
"isBuilding",
"buildStageState",
"lastCheckedAt",
"lastChangedAt",
"hasPendingChanges",
"pendingChanges",
"pipelineOutdated",
"rebuildRecommended",
"hasWebSource",
"hasDatasetSource",
"sourceUsage",
"sourceChunks",
"buildRestriction",
"refreshEnabled",
"refreshFrequency",
"refreshNextRunAt",
"refreshInFlight",
"openIssueCount",
"instructionCount",
"createdBy",
"createdAt",
"updatedAt"
],
"description": "A knowledge base and its current state."
},
"description": "The items on this page."
},
"nextCursor": {
"nullable": true,
"description": "The cursor for the next page. Pass it as `cursor` to get more results. `null` when there are no more pages.",
"type": "string"
}
},
"required": ["data", "nextCursor"],
"description": "A page of knowledge bases."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"post": {
"operationId": "createKnowledgeBase",
"summary": "Create a knowledge base",
"tags": ["knowledge-bases"],
"description": "Creates a knowledge base in your organization. To add content to it, create an import. If your organization's Context document store can't be used, the request returns `503` with code `contextStoreUnavailable` and you can retry.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"organizationId": {
"type": "string",
"minLength": 1,
"description": "The ID of the organization to create the knowledge base in."
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "The knowledge base's title."
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "A short description of what the knowledge base covers."
}
},
"required": ["organizationId", "title", "description"]
}
}
}
},
"parameters": [
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "Idempotency-Key",
"required": false,
"description": "A unique value, such as a UUID, that makes retries safe. A retry with the same key and body returns the first response instead of repeating the work."
}
],
"responses": {
"201": {
"description": "A knowledge base and its current state.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "An internal UUID for the knowledge base, still accepted wherever a `knowledgeBaseId` is expected. Use `publicId` instead."
},
"publicId": {
"type": "string",
"description": "The knowledge base's ID, such as `kb3do82whm`. Store this one, and pass it as `knowledgeBaseId` in paths and filters. Treat it as an opaque string."
},
"organizationId": {
"type": "string",
"description": "The ID of the organization that owns the knowledge base."
},
"title": {
"type": "string",
"description": "The knowledge base's title."
},
"description": {
"type": "string",
"description": "A short description of what the knowledge base covers."
},
"state": {
"type": "string",
"enum": ["created", "building", "ready", "review", "stale", "paused"],
"description": "The knowledge base's build state. `created`: not built yet. `ready`: built, with no open issues. `review`: built, with open issues to review. A failed build doesn't change the state. `building`, `stale`, and `paused` aren't currently returned. To check for a running build, use `isBuilding`."
},
"activeJobId": {
"nullable": true,
"description": "The job ID of the most recent build, or `null` if no build has started. Check its progress with `GET .../jobs/{jobId}`.",
"type": "string"
},
"isBuilding": {
"type": "boolean",
"description": "Whether a build is running now."
},
"buildStageState": {
"nullable": true,
"description": "Progress of the most recent build, by stage. `null` until a build reports progress. It can briefly belong to an earlier build, so use it only when its `jobId` matches `activeJobId`.",
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The ID of the build job this progress belongs to."
},
"stages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"tldr",
"map",
"triage",
"plan",
"organize",
"arrange",
"write",
"review",
"polish"
],
"description": "The stage's ID. Which stages a build runs can change between builds and knowledge bases, so handle IDs you don't recognize."
},
"status": {
"type": "string",
"enum": ["pending", "running", "done", "failed"],
"description": "The stage's status. `pending`: not started. `running`: in progress. `done`: finished. `failed`: the build ended before the stage finished."
},
"units": {
"description": "The stage's progress counts. Absent when the stage hasn't reported counts.",
"type": "object",
"properties": {
"unit": {
"type": "string",
"enum": ["sources", "groups", "entries", "rounds"],
"description": "What `done` and `total` count: `sources`, `groups` of related content, `entries`, or `rounds` of final fixes. A `rounds` stage has no `total`."
},
"done": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many units the stage has finished."
},
"total": {
"description": "How many units the stage will process. Absent when `unit` is `rounds`.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": ["unit", "done"]
}
},
"required": ["id", "status"]
},
"description": "The build's stages and their progress. Stages that haven't reported yet can be missing."
}
},
"required": ["jobId", "stages"]
},
"lastCheckedAt": {
"nullable": true,
"description": "When a refresh last checked the knowledge base for changes, whether or not anything changed. `null` until the first refresh.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"lastChangedAt": {
"nullable": true,
"description": "When the content last changed: the time of the most recent successful build. `null` if the knowledge base has never built.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"hasPendingChanges": {
"type": "boolean",
"description": "Whether sources were added, changed, or removed since the last successful build. A change a check already reviewed without filing an issue, or that a dismissed issue covered, no longer counts. Always `false` before the first build."
},
"pendingChanges": {
"nullable": true,
"description": "Counts of sources added, changed, and removed since the last successful build, excluding changes a check already reviewed without filing an issue or that a dismissed issue covered. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it. `null` in list responses and before the first build.",
"type": "object",
"properties": {
"added": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources added since the last successful build, including sources no successful build has included yet."
},
"changed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources whose content changed since the last successful build."
},
"removed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources that recent refreshes no longer find."
}
},
"required": ["added", "changed", "removed"]
},
"pipelineOutdated": {
"type": "boolean",
"description": "Whether Sanity Context has improved how it builds knowledge bases since the last successful build. Rebuild to apply the improvements. Always `false` before the first build."
},
"rebuildRecommended": {
"nullable": true,
"description": "A recommendation to rebuild, because new or changed content doesn't fit the current outline, or pages are out of date with changed sources and only a build updates them. `null` when there's no recommendation. A refresh where the content fits again, a successful build, or adding or removing sources clears it.",
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "Why a rebuild is recommended, written to show to users."
},
"at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the recommendation was made."
}
},
"required": ["reason", "at"]
},
"hasWebSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one website source."
},
"hasDatasetSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one Sanity dataset source."
},
"sourceUsage": {
"nullable": true,
"description": "How many sources the knowledge base uses, and its source limit.",
"type": "object",
"properties": {
"used": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources counted toward the limit, including parts split from large sources."
},
"limit": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The maximum number of sources the knowledge base can have."
}
},
"required": ["used", "limit"]
},
"sourceChunks": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of source chunks the knowledge base holds, in the sources counted by `sourceUsage`, whether or not they have been built. Sources still being processed add theirs once converted."
},
"buildRestriction": {
"nullable": true,
"description": "Why a build request would be denied right now, or `null` if you can build. Only `GET .../knowledge-bases/{knowledgeBaseId}` checks it. List and create responses always return `null`.",
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "A stable code for the restriction, such as `planLimitReached`."
},
"message": {
"type": "string",
"description": "A readable explanation that you can show to users."
}
},
"required": ["code", "message"]
},
"refreshEnabled": {
"type": "boolean",
"description": "Whether scheduled refresh is on. Only applies to knowledge bases with a website or dataset source."
},
"refreshFrequency": {
"type": "string",
"enum": ["weekly", "monthly"],
"description": "How often scheduled refresh runs: `weekly` (the default) or `monthly`."
},
"refreshNextRunAt": {
"nullable": true,
"description": "When the next scheduled refresh runs. `null` when scheduled refresh is off or not scheduled yet. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `null`.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"refreshInFlight": {
"type": "boolean",
"description": "Whether a refresh is running now. While it's `true`, a new refresh request doesn't start another one. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `false`."
},
"openIssueCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of open issues waiting for review. Always `0` before the first build."
},
"instructionCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of active instructions for the knowledge base."
},
"createdBy": {
"nullable": true,
"description": "Who created the knowledge base. `null` if unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was last updated."
}
},
"required": [
"id",
"publicId",
"organizationId",
"title",
"description",
"state",
"activeJobId",
"isBuilding",
"buildStageState",
"lastCheckedAt",
"lastChangedAt",
"hasPendingChanges",
"pendingChanges",
"pipelineOutdated",
"rebuildRecommended",
"hasWebSource",
"hasDatasetSource",
"sourceUsage",
"sourceChunks",
"buildRestriction",
"refreshEnabled",
"refreshFrequency",
"refreshNextRunAt",
"refreshInFlight",
"openIssueCount",
"instructionCount",
"createdBy",
"createdAt",
"updatedAt"
],
"description": "A knowledge base and its current state."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}": {
"get": {
"operationId": "getKnowledgeBase",
"summary": "Get a knowledge base",
"tags": ["knowledge-bases"],
"description": "Returns a knowledge base's metadata and state. `knowledgeBaseId` accepts the public ID (`kb...`) or the UUID, and you don't need to pass an organization. If you can't read the knowledge base, the request returns `404`. To read the built entries, query `sanity.context.entry` documents with GROQ from your organization's document store.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A knowledge base and its current state.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "An internal UUID for the knowledge base, still accepted wherever a `knowledgeBaseId` is expected. Use `publicId` instead."
},
"publicId": {
"type": "string",
"description": "The knowledge base's ID, such as `kb3do82whm`. Store this one, and pass it as `knowledgeBaseId` in paths and filters. Treat it as an opaque string."
},
"organizationId": {
"type": "string",
"description": "The ID of the organization that owns the knowledge base."
},
"title": {
"type": "string",
"description": "The knowledge base's title."
},
"description": {
"type": "string",
"description": "A short description of what the knowledge base covers."
},
"state": {
"type": "string",
"enum": ["created", "building", "ready", "review", "stale", "paused"],
"description": "The knowledge base's build state. `created`: not built yet. `ready`: built, with no open issues. `review`: built, with open issues to review. A failed build doesn't change the state. `building`, `stale`, and `paused` aren't currently returned. To check for a running build, use `isBuilding`."
},
"activeJobId": {
"nullable": true,
"description": "The job ID of the most recent build, or `null` if no build has started. Check its progress with `GET .../jobs/{jobId}`.",
"type": "string"
},
"isBuilding": {
"type": "boolean",
"description": "Whether a build is running now."
},
"buildStageState": {
"nullable": true,
"description": "Progress of the most recent build, by stage. `null` until a build reports progress. It can briefly belong to an earlier build, so use it only when its `jobId` matches `activeJobId`.",
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The ID of the build job this progress belongs to."
},
"stages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"tldr",
"map",
"triage",
"plan",
"organize",
"arrange",
"write",
"review",
"polish"
],
"description": "The stage's ID. Which stages a build runs can change between builds and knowledge bases, so handle IDs you don't recognize."
},
"status": {
"type": "string",
"enum": ["pending", "running", "done", "failed"],
"description": "The stage's status. `pending`: not started. `running`: in progress. `done`: finished. `failed`: the build ended before the stage finished."
},
"units": {
"description": "The stage's progress counts. Absent when the stage hasn't reported counts.",
"type": "object",
"properties": {
"unit": {
"type": "string",
"enum": ["sources", "groups", "entries", "rounds"],
"description": "What `done` and `total` count: `sources`, `groups` of related content, `entries`, or `rounds` of final fixes. A `rounds` stage has no `total`."
},
"done": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many units the stage has finished."
},
"total": {
"description": "How many units the stage will process. Absent when `unit` is `rounds`.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": ["unit", "done"]
}
},
"required": ["id", "status"]
},
"description": "The build's stages and their progress. Stages that haven't reported yet can be missing."
}
},
"required": ["jobId", "stages"]
},
"lastCheckedAt": {
"nullable": true,
"description": "When a refresh last checked the knowledge base for changes, whether or not anything changed. `null` until the first refresh.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"lastChangedAt": {
"nullable": true,
"description": "When the content last changed: the time of the most recent successful build. `null` if the knowledge base has never built.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"hasPendingChanges": {
"type": "boolean",
"description": "Whether sources were added, changed, or removed since the last successful build. A change a check already reviewed without filing an issue, or that a dismissed issue covered, no longer counts. Always `false` before the first build."
},
"pendingChanges": {
"nullable": true,
"description": "Counts of sources added, changed, and removed since the last successful build, excluding changes a check already reviewed without filing an issue or that a dismissed issue covered. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it. `null` in list responses and before the first build.",
"type": "object",
"properties": {
"added": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources added since the last successful build, including sources no successful build has included yet."
},
"changed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources whose content changed since the last successful build."
},
"removed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources that recent refreshes no longer find."
}
},
"required": ["added", "changed", "removed"]
},
"pipelineOutdated": {
"type": "boolean",
"description": "Whether Sanity Context has improved how it builds knowledge bases since the last successful build. Rebuild to apply the improvements. Always `false` before the first build."
},
"rebuildRecommended": {
"nullable": true,
"description": "A recommendation to rebuild, because new or changed content doesn't fit the current outline, or pages are out of date with changed sources and only a build updates them. `null` when there's no recommendation. A refresh where the content fits again, a successful build, or adding or removing sources clears it.",
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "Why a rebuild is recommended, written to show to users."
},
"at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the recommendation was made."
}
},
"required": ["reason", "at"]
},
"hasWebSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one website source."
},
"hasDatasetSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one Sanity dataset source."
},
"sourceUsage": {
"nullable": true,
"description": "How many sources the knowledge base uses, and its source limit.",
"type": "object",
"properties": {
"used": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources counted toward the limit, including parts split from large sources."
},
"limit": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The maximum number of sources the knowledge base can have."
}
},
"required": ["used", "limit"]
},
"sourceChunks": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of source chunks the knowledge base holds, in the sources counted by `sourceUsage`, whether or not they have been built. Sources still being processed add theirs once converted."
},
"buildRestriction": {
"nullable": true,
"description": "Why a build request would be denied right now, or `null` if you can build. Only `GET .../knowledge-bases/{knowledgeBaseId}` checks it. List and create responses always return `null`.",
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "A stable code for the restriction, such as `planLimitReached`."
},
"message": {
"type": "string",
"description": "A readable explanation that you can show to users."
}
},
"required": ["code", "message"]
},
"refreshEnabled": {
"type": "boolean",
"description": "Whether scheduled refresh is on. Only applies to knowledge bases with a website or dataset source."
},
"refreshFrequency": {
"type": "string",
"enum": ["weekly", "monthly"],
"description": "How often scheduled refresh runs: `weekly` (the default) or `monthly`."
},
"refreshNextRunAt": {
"nullable": true,
"description": "When the next scheduled refresh runs. `null` when scheduled refresh is off or not scheduled yet. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `null`.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"refreshInFlight": {
"type": "boolean",
"description": "Whether a refresh is running now. While it's `true`, a new refresh request doesn't start another one. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `false`."
},
"openIssueCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of open issues waiting for review. Always `0` before the first build."
},
"instructionCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of active instructions for the knowledge base."
},
"createdBy": {
"nullable": true,
"description": "Who created the knowledge base. `null` if unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was last updated."
}
},
"required": [
"id",
"publicId",
"organizationId",
"title",
"description",
"state",
"activeJobId",
"isBuilding",
"buildStageState",
"lastCheckedAt",
"lastChangedAt",
"hasPendingChanges",
"pendingChanges",
"pipelineOutdated",
"rebuildRecommended",
"hasWebSource",
"hasDatasetSource",
"sourceUsage",
"sourceChunks",
"buildRestriction",
"refreshEnabled",
"refreshFrequency",
"refreshNextRunAt",
"refreshInFlight",
"openIssueCount",
"instructionCount",
"createdBy",
"createdAt",
"updatedAt"
],
"description": "A knowledge base and its current state."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"patch": {
"operationId": "updateKnowledgeBase",
"summary": "Update a knowledge base",
"tags": ["knowledge-bases"],
"description": "Updates the title, the description, or the recurring refresh settings (`refreshEnabled` and `refreshFrequency`). Fields equal to their current value are ignored, so sending the current values changes nothing. Changing a refresh field on a knowledge base with no website or dataset source returns `422` with code `refreshControlsUnavailable`. Setting `refreshEnabled` to `false` pauses the schedule, and you can still start a refresh manually.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"title": {
"description": "The knowledge base's new title.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"description": {
"description": "The knowledge base's new description.",
"type": "string",
"minLength": 1,
"maxLength": 2000
},
"refreshEnabled": {
"description": "Whether scheduled refresh is on. Turning it off stops only scheduled refreshes, so you can still start a refresh yourself. Turning it on requires a plan that includes scheduled refresh. Requires a website or dataset source.",
"type": "boolean"
},
"refreshFrequency": {
"description": "How often scheduled refresh runs: `weekly` or `monthly`. Requires a website or dataset source and a plan that includes scheduled refresh.",
"type": "string",
"enum": ["weekly", "monthly"]
}
}
}
}
}
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A knowledge base and its current state.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "An internal UUID for the knowledge base, still accepted wherever a `knowledgeBaseId` is expected. Use `publicId` instead."
},
"publicId": {
"type": "string",
"description": "The knowledge base's ID, such as `kb3do82whm`. Store this one, and pass it as `knowledgeBaseId` in paths and filters. Treat it as an opaque string."
},
"organizationId": {
"type": "string",
"description": "The ID of the organization that owns the knowledge base."
},
"title": {
"type": "string",
"description": "The knowledge base's title."
},
"description": {
"type": "string",
"description": "A short description of what the knowledge base covers."
},
"state": {
"type": "string",
"enum": ["created", "building", "ready", "review", "stale", "paused"],
"description": "The knowledge base's build state. `created`: not built yet. `ready`: built, with no open issues. `review`: built, with open issues to review. A failed build doesn't change the state. `building`, `stale`, and `paused` aren't currently returned. To check for a running build, use `isBuilding`."
},
"activeJobId": {
"nullable": true,
"description": "The job ID of the most recent build, or `null` if no build has started. Check its progress with `GET .../jobs/{jobId}`.",
"type": "string"
},
"isBuilding": {
"type": "boolean",
"description": "Whether a build is running now."
},
"buildStageState": {
"nullable": true,
"description": "Progress of the most recent build, by stage. `null` until a build reports progress. It can briefly belong to an earlier build, so use it only when its `jobId` matches `activeJobId`.",
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The ID of the build job this progress belongs to."
},
"stages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"tldr",
"map",
"triage",
"plan",
"organize",
"arrange",
"write",
"review",
"polish"
],
"description": "The stage's ID. Which stages a build runs can change between builds and knowledge bases, so handle IDs you don't recognize."
},
"status": {
"type": "string",
"enum": ["pending", "running", "done", "failed"],
"description": "The stage's status. `pending`: not started. `running`: in progress. `done`: finished. `failed`: the build ended before the stage finished."
},
"units": {
"description": "The stage's progress counts. Absent when the stage hasn't reported counts.",
"type": "object",
"properties": {
"unit": {
"type": "string",
"enum": ["sources", "groups", "entries", "rounds"],
"description": "What `done` and `total` count: `sources`, `groups` of related content, `entries`, or `rounds` of final fixes. A `rounds` stage has no `total`."
},
"done": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many units the stage has finished."
},
"total": {
"description": "How many units the stage will process. Absent when `unit` is `rounds`.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": ["unit", "done"]
}
},
"required": ["id", "status"]
},
"description": "The build's stages and their progress. Stages that haven't reported yet can be missing."
}
},
"required": ["jobId", "stages"]
},
"lastCheckedAt": {
"nullable": true,
"description": "When a refresh last checked the knowledge base for changes, whether or not anything changed. `null` until the first refresh.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"lastChangedAt": {
"nullable": true,
"description": "When the content last changed: the time of the most recent successful build. `null` if the knowledge base has never built.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"hasPendingChanges": {
"type": "boolean",
"description": "Whether sources were added, changed, or removed since the last successful build. A change a check already reviewed without filing an issue, or that a dismissed issue covered, no longer counts. Always `false` before the first build."
},
"pendingChanges": {
"nullable": true,
"description": "Counts of sources added, changed, and removed since the last successful build, excluding changes a check already reviewed without filing an issue or that a dismissed issue covered. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it. `null` in list responses and before the first build.",
"type": "object",
"properties": {
"added": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources added since the last successful build, including sources no successful build has included yet."
},
"changed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources whose content changed since the last successful build."
},
"removed": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Sources that recent refreshes no longer find."
}
},
"required": ["added", "changed", "removed"]
},
"pipelineOutdated": {
"type": "boolean",
"description": "Whether Sanity Context has improved how it builds knowledge bases since the last successful build. Rebuild to apply the improvements. Always `false` before the first build."
},
"rebuildRecommended": {
"nullable": true,
"description": "A recommendation to rebuild, because new or changed content doesn't fit the current outline, or pages are out of date with changed sources and only a build updates them. `null` when there's no recommendation. A refresh where the content fits again, a successful build, or adding or removing sources clears it.",
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "Why a rebuild is recommended, written to show to users."
},
"at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the recommendation was made."
}
},
"required": ["reason", "at"]
},
"hasWebSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one website source."
},
"hasDatasetSource": {
"type": "boolean",
"description": "Whether the knowledge base has at least one Sanity dataset source."
},
"sourceUsage": {
"nullable": true,
"description": "How many sources the knowledge base uses, and its source limit.",
"type": "object",
"properties": {
"used": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources counted toward the limit, including parts split from large sources."
},
"limit": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The maximum number of sources the knowledge base can have."
}
},
"required": ["used", "limit"]
},
"sourceChunks": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of source chunks the knowledge base holds, in the sources counted by `sourceUsage`, whether or not they have been built. Sources still being processed add theirs once converted."
},
"buildRestriction": {
"nullable": true,
"description": "Why a build request would be denied right now, or `null` if you can build. Only `GET .../knowledge-bases/{knowledgeBaseId}` checks it. List and create responses always return `null`.",
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "A stable code for the restriction, such as `planLimitReached`."
},
"message": {
"type": "string",
"description": "A readable explanation that you can show to users."
}
},
"required": ["code", "message"]
},
"refreshEnabled": {
"type": "boolean",
"description": "Whether scheduled refresh is on. Only applies to knowledge bases with a website or dataset source."
},
"refreshFrequency": {
"type": "string",
"enum": ["weekly", "monthly"],
"description": "How often scheduled refresh runs: `weekly` (the default) or `monthly`."
},
"refreshNextRunAt": {
"nullable": true,
"description": "When the next scheduled refresh runs. `null` when scheduled refresh is off or not scheduled yet. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `null`.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"refreshInFlight": {
"type": "boolean",
"description": "Whether a refresh is running now. While it's `true`, a new refresh request doesn't start another one. Only `GET .../knowledge-bases/{knowledgeBaseId}` computes it, so list responses return `false`."
},
"openIssueCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of open issues waiting for review. Always `0` before the first build."
},
"instructionCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of active instructions for the knowledge base."
},
"createdBy": {
"nullable": true,
"description": "Who created the knowledge base. `null` if unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was created."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the knowledge base was last updated."
}
},
"required": [
"id",
"publicId",
"organizationId",
"title",
"description",
"state",
"activeJobId",
"isBuilding",
"buildStageState",
"lastCheckedAt",
"lastChangedAt",
"hasPendingChanges",
"pendingChanges",
"pipelineOutdated",
"rebuildRecommended",
"hasWebSource",
"hasDatasetSource",
"sourceUsage",
"sourceChunks",
"buildRestriction",
"refreshEnabled",
"refreshFrequency",
"refreshNextRunAt",
"refreshInFlight",
"openIssueCount",
"instructionCount",
"createdBy",
"createdAt",
"updatedAt"
],
"description": "A knowledge base and its current state."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"delete": {
"operationId": "deleteKnowledgeBase",
"summary": "Delete a knowledge base",
"tags": ["knowledge-bases"],
"description": "Deletes the knowledge base and everything it owns: its sources, imports, revisions, stored source files, and its documents in your organization's document store. While a build, refresh, apply, or import is running, the request returns `409` with code `buildInFlight`. Retry after that work finishes.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"204": {
"description": "The knowledge base was deleted.",
"content": {
"application/json": {
"schema": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "The knowledge base was deleted."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/build": {
"post": {
"operationId": "buildKnowledgeBase",
"summary": "Start a knowledge base build",
"tags": ["knowledge-bases"],
"description": "Queues a build over the knowledge base's current sources and returns a job ID immediately. If a build is already running, the response returns that build's job ID instead of starting a second build.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "Idempotency-Key",
"required": false,
"description": "A unique value, such as a UUID, that makes retries safe. A retry with the same key and body returns the first response instead of repeating the work."
}
],
"responses": {
"202": {
"description": "A queued job that you can poll for progress.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The queued job's ID. Check its progress with `GET .../jobs/{jobId}`. Treat it as an opaque string. Its format can change."
}
},
"required": ["jobId"],
"description": "A queued job that you can poll for progress."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/build/cancel": {
"post": {
"operationId": "cancelKnowledgeBaseBuild",
"summary": "Cancel a knowledge base build",
"tags": ["knowledge-bases"],
"description": "Cancels the running build and resets the knowledge base so you can build it again. Returns `cancelled: false` when no build is running.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "The result of the cancel request.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"cancelled": {
"type": "boolean",
"description": "Whether a running build was cancelled. `false` when no build was running."
}
},
"required": ["cancelled"],
"description": "The result of the cancel request."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/refresh": {
"post": {
"operationId": "refreshKnowledgeBase",
"summary": "Refresh a knowledge base",
"tags": ["knowledge-bases"],
"description": "Queues a refresh that recrawls website sources, re-syncs dataset sources, compares the result with the last build, and files issues for what changed. Returns a job ID. If a refresh is already running, the response has `started: false` and that refresh's job ID. Supports the `Idempotency-Key` header.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "Idempotency-Key",
"required": false,
"description": "A unique value, such as a UUID, that makes retries safe. A retry with the same key and body returns the first response instead of repeating the work."
}
],
"responses": {
"202": {
"description": "A queued refresh job that you can poll for progress.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The queued job's ID. Check its progress with `GET .../jobs/{jobId}`. Treat it as an opaque string. Its format can change."
},
"started": {
"type": "boolean",
"description": "Whether this request started a new refresh. `false` means a refresh was already running, and `jobId` is that refresh."
}
},
"required": ["jobId", "started"],
"description": "A queued refresh job that you can poll for progress."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/sources": {
"get": {
"operationId": "listSources",
"summary": "List sources",
"tags": ["sources"],
"description": "Lists the sources in a knowledge base: the pages, files, and documents that imports produce and builds cite. Sources are read-only. To add content, create an import. Results are cursor-paginated, and you can filter them by `status`.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "cursor",
"required": false,
"description": "The `nextCursor` value from the previous page. Omit it to get the first page."
},
{
"schema": {
"default": 50,
"type": "integer",
"minimum": 1,
"maximum": 200
},
"in": "query",
"name": "limit",
"required": false,
"description": "The maximum number of items to return."
},
{
"schema": {
"type": "string",
"enum": ["pending", "processing", "ready", "failed", "skipped"]
},
"in": "query",
"name": "status",
"required": false,
"description": "Return only sources with this status."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "query",
"name": "importId",
"required": false,
"description": "Return only the sources that this import produced."
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "ids",
"required": false,
"description": "Comma-separated IDs of the sources to return, up to 200. Includes the parts of large sources that were split, which the default list leaves out. When set, `status` and `cursor` are ignored and every matching source is returned in one page."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A page of sources.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The source's ID."
},
"knowledgeBaseId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The `id` of the knowledge base that the source belongs to."
},
"filename": {
"type": "string",
"description": "The source's name: the file name for an upload, the page title for a web page, or the document title for a dataset document."
},
"kind": {
"type": "string",
"enum": ["web", "file", "dataset"],
"description": "Where the source came from. `web`: a crawled web page. `file`: an uploaded file or inline text. `dataset`: a document from a Sanity dataset."
},
"sizeBytes": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The source's size in bytes."
},
"chunks": {
"nullable": true,
"description": "The number of source chunks the source counts toward usage. A source split into parts reports its parts' total. `null` until the source is converted, and for a source that failed or whose file type or size was skipped.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"status": {
"type": "string",
"enum": ["pending", "processing", "ready", "failed", "skipped"],
"description": "The source's processing status. `pending`: waiting to be processed. `processing`: distilled and being summarized. `ready`: processed and available to builds. `failed`: couldn't be processed. `skipped`: not processed, because its file type isn't supported, it's too large, or it was split into smaller sources."
},
"tldr": {
"nullable": true,
"description": "A short summary of the source. `null` until the source is summarized.",
"type": "string"
},
"topics": {
"nullable": true,
"description": "Topics the source covers. `null` until the source is summarized.",
"type": "array",
"items": {
"type": "string"
}
},
"canonicalUrl": {
"nullable": true,
"description": "The page URL of a `web` source. `null` for other kinds.",
"type": "string"
},
"externalId": {
"nullable": true,
"description": "The `_id` of the Sanity document a `dataset` source came from. Use it to find the document in your studio. `null` for other kinds.",
"type": "string"
},
"fetchedAt": {
"nullable": true,
"description": "When the source's content was last fetched.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"documentUpdatedAt": {
"nullable": true,
"description": "When the document itself was last updated, as it says: a page's meta tags, a dataset document's `_updatedAt`, or the metadata in a PDF, Office or markdown file. A section of a document has its document's date. `null` when the document doesn't say. When an uploaded file disagrees with a document more than a year newer, builds use the newer document's value and ask nobody. A page or dataset document is never replaced this way: the disagreement is asked.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"distilledAt": {
"nullable": true,
"description": "When the source's content was last distilled into markdown. `null` until it's distilled.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the source was added."
}
},
"required": [
"id",
"knowledgeBaseId",
"filename",
"kind",
"sizeBytes",
"chunks",
"status",
"tldr",
"topics",
"canonicalUrl",
"externalId",
"fetchedAt",
"documentUpdatedAt",
"distilledAt",
"createdAt"
],
"description": "A page, file, or document that an import produced and that builds cite."
},
"description": "The items on this page."
},
"nextCursor": {
"nullable": true,
"description": "The cursor for the next page. Pass it as `cursor` to get more results. `null` when there are no more pages.",
"type": "string"
}
},
"required": ["data", "nextCursor"],
"description": "A page of sources."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/sources/{sourceId}": {
"get": {
"operationId": "getSource",
"summary": "Get a source",
"tags": ["sources"],
"description": "Returns a source with its metadata and processing status.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "sourceId",
"required": true,
"description": "The source's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A page, file, or document that an import produced and that builds cite.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The source's ID."
},
"knowledgeBaseId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The `id` of the knowledge base that the source belongs to."
},
"filename": {
"type": "string",
"description": "The source's name: the file name for an upload, the page title for a web page, or the document title for a dataset document."
},
"kind": {
"type": "string",
"enum": ["web", "file", "dataset"],
"description": "Where the source came from. `web`: a crawled web page. `file`: an uploaded file or inline text. `dataset`: a document from a Sanity dataset."
},
"sizeBytes": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The source's size in bytes."
},
"chunks": {
"nullable": true,
"description": "The number of source chunks the source counts toward usage. A source split into parts reports its parts' total. `null` until the source is converted, and for a source that failed or whose file type or size was skipped.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"status": {
"type": "string",
"enum": ["pending", "processing", "ready", "failed", "skipped"],
"description": "The source's processing status. `pending`: waiting to be processed. `processing`: distilled and being summarized. `ready`: processed and available to builds. `failed`: couldn't be processed. `skipped`: not processed, because its file type isn't supported, it's too large, or it was split into smaller sources."
},
"tldr": {
"nullable": true,
"description": "A short summary of the source. `null` until the source is summarized.",
"type": "string"
},
"topics": {
"nullable": true,
"description": "Topics the source covers. `null` until the source is summarized.",
"type": "array",
"items": {
"type": "string"
}
},
"canonicalUrl": {
"nullable": true,
"description": "The page URL of a `web` source. `null` for other kinds.",
"type": "string"
},
"externalId": {
"nullable": true,
"description": "The `_id` of the Sanity document a `dataset` source came from. Use it to find the document in your studio. `null` for other kinds.",
"type": "string"
},
"fetchedAt": {
"nullable": true,
"description": "When the source's content was last fetched.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"documentUpdatedAt": {
"nullable": true,
"description": "When the document itself was last updated, as it says: a page's meta tags, a dataset document's `_updatedAt`, or the metadata in a PDF, Office or markdown file. A section of a document has its document's date. `null` when the document doesn't say. When an uploaded file disagrees with a document more than a year newer, builds use the newer document's value and ask nobody. A page or dataset document is never replaced this way: the disagreement is asked.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"distilledAt": {
"nullable": true,
"description": "When the source's content was last distilled into markdown. `null` until it's distilled.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the source was added."
}
},
"required": [
"id",
"knowledgeBaseId",
"filename",
"kind",
"sizeBytes",
"chunks",
"status",
"tldr",
"topics",
"canonicalUrl",
"externalId",
"fetchedAt",
"documentUpdatedAt",
"distilledAt",
"createdAt"
],
"description": "A page, file, or document that an import produced and that builds cite."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"delete": {
"operationId": "deleteSource",
"summary": "Delete a source",
"tags": ["sources"],
"description": "Deletes the source immediately. Entries that cite it stay the same until the next build or refresh, which removes the citations and deletes any entry left with no sources.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "sourceId",
"required": true,
"description": "The source's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"204": {
"description": "The source was deleted.",
"content": {
"application/json": {
"schema": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "The source was deleted."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/sources/{sourceId}/content": {
"get": {
"operationId": "getSourceContent",
"summary": "Get a source's distilled content",
"tags": ["sources"],
"description": "Returns the source's distilled content: the markdown extracted from the original page, file, or document, which is the text builds cite. Use it to check an issue's claims against the sources listed in its `citedSourceIds`. To fetch a range of lines, set `startLine` and `endLine` (1-indexed, inclusive). The response is JSON by default. Set `format` to `markdown` or `plain` to get the text alone. Until the source finishes processing, the request returns `409` with code `sourceNotDistilled`.",
"parameters": [
{
"schema": {
"type": "string",
"enum": ["json", "markdown", "plain"]
},
"in": "query",
"name": "format",
"required": false,
"description": "Response format. `json` (default) returns the structured resource. `markdown` and `plain` return the content as rendered text, ready to pass to a model."
},
{
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"in": "query",
"name": "startLine",
"required": false,
"description": "The first line to return, starting at 1. Omit `startLine` and `endLine` to get the whole content."
},
{
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"in": "query",
"name": "endLine",
"required": false,
"description": "The last line to return, inclusive. A value past the end returns everything up to the last line."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "sourceId",
"required": true,
"description": "The source's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A source's distilled markdown, or a range of its lines.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"sourceId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The source's ID."
},
"content": {
"type": "string",
"description": "The distilled markdown, or the requested lines of it."
},
"totalLines": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of lines in the full distilled content."
},
"slice": {
"type": "object",
"properties": {
"start": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The first line returned."
},
"end": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The last line returned."
}
},
"required": ["start", "end"],
"description": "The range of lines returned, 1-indexed and inclusive. It can be shorter than requested when the range runs past the end. Both values are `0` when no lines are returned."
}
},
"required": ["sourceId", "content", "totalLines", "slice"],
"description": "A source's distilled markdown, or a range of its lines."
}
},
"text/markdown": {
"schema": {
"type": "string"
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/entries/{entryPath}/rebuild": {
"post": {
"operationId": "rebuildEntry",
"summary": "Rebuild an entry from its sources",
"tags": ["entries"],
"description": "Queues a rewrite of the entry at `entryPath` from its cited sources and the active instructions, and returns a job ID immediately. The response also lists the other entries built from any of the same sources. An instruction applies to every entry built from its sources, so those entries can change too. Returns `422` with code `entryDocumentInvalid` if the entry document was edited into a shape the API cannot read.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "entryPath",
"required": true,
"description": "The entry's slash-delimited path, such as `pricing/plans/free`, URL-encoded."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"202": {
"description": "The job that rebuilds the entry, and the other entries that share its sources.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "ID of the job that rebuilds the entry. Poll it with `GET .../jobs/{jobId}`."
},
"affectedEntries": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The entry's document ID."
},
"path": {
"type": "string",
"description": "The entry's path, such as `products/api/webhooks`."
},
"title": {
"type": "string",
"description": "The entry's title."
}
},
"required": ["id", "path", "title"],
"description": "Another entry that cites one of the same sources as the rebuilt entry."
},
"description": "Other entries built from any of this entry's sources. An instruction applies to every entry built from its sources, so these entries can change when they are next rebuilt."
}
},
"required": ["jobId", "affectedEntries"],
"description": "The job that rebuilds the entry, and the other entries that share its sources."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/imports": {
"get": {
"operationId": "listImports",
"summary": "List imports",
"tags": ["imports"],
"description": "Lists everything added to a knowledge base, one item per import: a file upload, website crawl, Sanity dataset, or inline text. Results are cursor-paginated. To list the sources each import produced, use `GET .../sources`.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "cursor",
"required": false,
"description": "The `nextCursor` value from the previous page. Omit it to get the first page."
},
{
"schema": {
"default": 50,
"type": "integer",
"minimum": 1,
"maximum": 200
},
"in": "query",
"name": "limit",
"required": false,
"description": "The maximum number of items to return."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A page of imports.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The import's ID."
},
"knowledgeBaseId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The `id` of the knowledge base that the import belongs to."
},
"name": {
"nullable": true,
"description": "A label for the import: the file name for an upload, the root URL for a crawl, a label for a dataset query, or the title for inline text.",
"type": "string"
},
"sizeBytes": {
"nullable": true,
"description": "The size of the uploaded file or inline text, in bytes. `null` for crawl and dataset imports, and until a file upload completes.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"status": {
"type": "string",
"enum": ["uploading", "processing", "complete", "failed"],
"description": "The import's status. `uploading`: waiting for the file upload to complete. `processing`: content is being fetched and processed. `complete`: processing finished. `failed`: the import, or at least one of its sources, couldn't be processed. See `statusDetail` and `error` for details."
},
"sourceKind": {
"type": "string",
"enum": ["web", "file", "dataset"],
"description": "The kind of sources the import produces. `file`: uploads and inline text. `web`: crawls. `dataset`: Sanity datasets."
},
"lastCheckedAt": {
"nullable": true,
"description": "When the import's website or dataset was last checked, even if nothing changed. `null` for file and text imports, and before the first check.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"sourceCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources the import produced, such as crawled pages or files in an archive. Doesn't count parts split from large sources."
},
"sourceChunks": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of source chunks in the import's sources, including parts split from large sources. Sources still being processed add theirs once converted."
},
"totalDistillableCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources expected to be distilled, including parts split from large sources. Excludes skipped sources."
},
"distilledCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources distilled so far. Compare it with `totalDistillableCount` to show progress."
},
"unsupportedCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources skipped because their file type isn't supported, such as images."
},
"statusDetail": {
"nullable": true,
"description": "A note about the import's outcome, written to show to users. It explains a failure or a partial result, such as a crawl that stopped at the source limit. `null` when there's nothing to note. Prefer it over `error`.",
"type": "string"
},
"error": {
"nullable": true,
"description": "When `status` is `failed`, a readable reason from one failed source. `null` for any other status, or when no single source failed.",
"type": "string"
},
"crawlOptions": {
"nullable": true,
"description": "The options the next crawl of this website uses. An empty object means the defaults. `null` for other import types, and for a crawl whose root URL was removed.",
"type": "object",
"properties": {
"includePaths": {
"description": "Regular expressions for URL paths to crawl. When set, the crawl only includes pages whose path matches one of them.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"excludePaths": {
"description": "Regular expressions for URL paths to skip. Pages whose path matches one of them aren't crawled.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"maxDepth": {
"description": "How many levels deep the crawl goes from the root URL.",
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true,
"maximum": 9007199254740991
},
"sitemapOnly": {
"description": "Whether to crawl only the pages listed in the site's sitemap.",
"type": "boolean"
},
"ignoreQueryParameters": {
"description": "Whether to treat URLs that differ only by query string as one page. New crawls set it to `true` unless you set it. Set it to `false` when the query string selects different content, such as pagination.",
"type": "boolean"
},
"pageLimit": {
"description": "The maximum number of pages to crawl. The crawl can stop sooner when the knowledge base reaches its source limit.",
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true,
"maximum": 5000
}
}
},
"datasetSource": {
"nullable": true,
"description": "The Sanity project, dataset, and full query a dataset import reads from. `null` for other import types.",
"type": "object",
"properties": {
"sanityProjectId": {
"type": "string",
"description": "The ID of the Sanity project the documents come from."
},
"sanityDatasetId": {
"type": "string",
"description": "The dataset the documents come from."
},
"query": {
"type": "string",
"description": "The full GROQ query that selects the documents, exactly as saved."
}
},
"required": ["sanityProjectId", "sanityDatasetId", "query"]
},
"createdBy": {
"nullable": true,
"description": "Who added the import. `null` if unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the import was created."
},
"completedAt": {
"nullable": true,
"description": "When processing finished, whether it succeeded or failed. `null` while the import is uploading or processing.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"knowledgeBaseId",
"name",
"sizeBytes",
"status",
"sourceKind",
"lastCheckedAt",
"sourceCount",
"sourceChunks",
"totalDistillableCount",
"distilledCount",
"unsupportedCount",
"statusDetail",
"error",
"crawlOptions",
"datasetSource",
"createdBy",
"createdAt",
"completedAt"
],
"description": "Content added to a knowledge base: a file upload, website crawl, Sanity dataset, or inline text."
},
"description": "The items on this page."
},
"nextCursor": {
"nullable": true,
"description": "The cursor for the next page. Pass it as `cursor` to get more results. `null` when there are no more pages.",
"type": "string"
}
},
"required": ["data", "nextCursor"],
"description": "A page of imports."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"post": {
"operationId": "createImport",
"summary": "Create a text, crawl, or dataset import",
"tags": ["imports"],
"description": "Adds content to a knowledge base. Set `type` to choose what to import:\n\n- `text`: inline content\n- `crawl`: a website\n- `dataset`: documents from a Sanity dataset, selected by a GROQ filter\n\nEach import queues processing and returns a job ID to poll. To import a file, use `POST .../imports/uploads` instead.\n\nAdding a crawl URL that already exists returns `409` with code `webSourceRootConflict`. Adding more crawl URLs than your limit allows returns `409` with code `webSourceRootLimitExceeded`. Supports the `Idempotency-Key` header.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["text"],
"description": "The import type. `text` imports inline content."
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "The import's title, shown in the list of imports."
},
"content": {
"type": "string",
"minLength": 1,
"maxLength": 1000000,
"description": "The text or markdown to import, up to 1,000,000 bytes of UTF-8."
},
"contentType": {
"default": "text/markdown",
"description": "The format of `content`: `text/markdown` (the default) or `text/plain`.",
"type": "string",
"enum": ["text/markdown", "text/plain"]
}
},
"required": ["type", "title", "content"]
},
{
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "The URL to start crawling from. It must be a public `http` or `https` URL."
},
"options": {
"description": "Options for the crawl. Options you omit use the defaults.",
"type": "object",
"properties": {
"includePaths": {
"description": "Regular expressions for URL paths to crawl. When set, the crawl only includes pages whose path matches one of them.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"excludePaths": {
"description": "Regular expressions for URL paths to skip. Pages whose path matches one of them aren't crawled.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"maxDepth": {
"description": "How many levels deep the crawl goes from the root URL.",
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true,
"maximum": 9007199254740991
},
"sitemapOnly": {
"description": "Whether to crawl only the pages listed in the site's sitemap.",
"type": "boolean"
},
"ignoreQueryParameters": {
"description": "Whether to treat URLs that differ only by query string as one page. New crawls set it to `true` unless you set it. Set it to `false` when the query string selects different content, such as pagination.",
"type": "boolean"
},
"pageLimit": {
"description": "The maximum number of pages to crawl. The crawl can stop sooner when the knowledge base reaches its source limit.",
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true,
"maximum": 5000
}
}
},
"type": {
"type": "string",
"enum": ["crawl"],
"description": "The import type. `crawl` imports a website."
}
},
"required": ["url", "type"]
},
{
"type": "object",
"properties": {
"sanityProjectId": {
"type": "string",
"minLength": 1,
"description": "The ID of the Sanity project to read documents from. You need full read access to the dataset and, on its project, the Administrator or Developer role or a custom role that can create datasets."
},
"sanityDatasetId": {
"type": "string",
"minLength": 1,
"description": "The dataset to read documents from, in the project set by `sanityProjectId`."
},
"query": {
"type": "string",
"minLength": 1,
"maxLength": 10000,
"description": "A GROQ query that selects the documents to import, with an optional projection. It can match up to 5,000 documents. Each refresh runs the query again."
},
"type": {
"type": "string",
"enum": ["dataset"],
"description": "The import type. `dataset` imports documents from a Sanity dataset."
}
},
"required": ["sanityProjectId", "sanityDatasetId", "query", "type"]
}
],
"description": "Content to add to a knowledge base. The `type` field sets the kind of import."
}
}
},
"description": "Content to add to a knowledge base. The `type` field sets the kind of import."
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "Idempotency-Key",
"required": false,
"description": "A unique value, such as a UUID, that makes retries safe. A retry with the same key and body returns the first response instead of repeating the work."
}
],
"responses": {
"202": {
"description": "A queued job that you can poll for progress.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The queued job's ID. Check its progress with `GET .../jobs/{jobId}`. Treat it as an opaque string. Its format can change."
}
},
"required": ["jobId"],
"description": "A queued job that you can poll for progress."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/imports/{importId}": {
"get": {
"operationId": "getImport",
"summary": "Get an import",
"tags": ["imports"],
"description": "Returns an import with its `sourceKind` and processing `status`.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "importId",
"required": true,
"description": "The import's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "Content added to a knowledge base: a file upload, website crawl, Sanity dataset, or inline text.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The import's ID."
},
"knowledgeBaseId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The `id` of the knowledge base that the import belongs to."
},
"name": {
"nullable": true,
"description": "A label for the import: the file name for an upload, the root URL for a crawl, a label for a dataset query, or the title for inline text.",
"type": "string"
},
"sizeBytes": {
"nullable": true,
"description": "The size of the uploaded file or inline text, in bytes. `null` for crawl and dataset imports, and until a file upload completes.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"status": {
"type": "string",
"enum": ["uploading", "processing", "complete", "failed"],
"description": "The import's status. `uploading`: waiting for the file upload to complete. `processing`: content is being fetched and processed. `complete`: processing finished. `failed`: the import, or at least one of its sources, couldn't be processed. See `statusDetail` and `error` for details."
},
"sourceKind": {
"type": "string",
"enum": ["web", "file", "dataset"],
"description": "The kind of sources the import produces. `file`: uploads and inline text. `web`: crawls. `dataset`: Sanity datasets."
},
"lastCheckedAt": {
"nullable": true,
"description": "When the import's website or dataset was last checked, even if nothing changed. `null` for file and text imports, and before the first check.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"sourceCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources the import produced, such as crawled pages or files in an archive. Doesn't count parts split from large sources."
},
"sourceChunks": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of source chunks in the import's sources, including parts split from large sources. Sources still being processed add theirs once converted."
},
"totalDistillableCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources expected to be distilled, including parts split from large sources. Excludes skipped sources."
},
"distilledCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources distilled so far. Compare it with `totalDistillableCount` to show progress."
},
"unsupportedCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The number of sources skipped because their file type isn't supported, such as images."
},
"statusDetail": {
"nullable": true,
"description": "A note about the import's outcome, written to show to users. It explains a failure or a partial result, such as a crawl that stopped at the source limit. `null` when there's nothing to note. Prefer it over `error`.",
"type": "string"
},
"error": {
"nullable": true,
"description": "When `status` is `failed`, a readable reason from one failed source. `null` for any other status, or when no single source failed.",
"type": "string"
},
"crawlOptions": {
"nullable": true,
"description": "The options the next crawl of this website uses. An empty object means the defaults. `null` for other import types, and for a crawl whose root URL was removed.",
"type": "object",
"properties": {
"includePaths": {
"description": "Regular expressions for URL paths to crawl. When set, the crawl only includes pages whose path matches one of them.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"excludePaths": {
"description": "Regular expressions for URL paths to skip. Pages whose path matches one of them aren't crawled.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"maxDepth": {
"description": "How many levels deep the crawl goes from the root URL.",
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true,
"maximum": 9007199254740991
},
"sitemapOnly": {
"description": "Whether to crawl only the pages listed in the site's sitemap.",
"type": "boolean"
},
"ignoreQueryParameters": {
"description": "Whether to treat URLs that differ only by query string as one page. New crawls set it to `true` unless you set it. Set it to `false` when the query string selects different content, such as pagination.",
"type": "boolean"
},
"pageLimit": {
"description": "The maximum number of pages to crawl. The crawl can stop sooner when the knowledge base reaches its source limit.",
"type": "integer",
"minimum": 0,
"exclusiveMinimum": true,
"maximum": 5000
}
}
},
"datasetSource": {
"nullable": true,
"description": "The Sanity project, dataset, and full query a dataset import reads from. `null` for other import types.",
"type": "object",
"properties": {
"sanityProjectId": {
"type": "string",
"description": "The ID of the Sanity project the documents come from."
},
"sanityDatasetId": {
"type": "string",
"description": "The dataset the documents come from."
},
"query": {
"type": "string",
"description": "The full GROQ query that selects the documents, exactly as saved."
}
},
"required": ["sanityProjectId", "sanityDatasetId", "query"]
},
"createdBy": {
"nullable": true,
"description": "Who added the import. `null` if unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the import was created."
},
"completedAt": {
"nullable": true,
"description": "When processing finished, whether it succeeded or failed. `null` while the import is uploading or processing.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"knowledgeBaseId",
"name",
"sizeBytes",
"status",
"sourceKind",
"lastCheckedAt",
"sourceCount",
"sourceChunks",
"totalDistillableCount",
"distilledCount",
"unsupportedCount",
"statusDetail",
"error",
"crawlOptions",
"datasetSource",
"createdBy",
"createdAt",
"completedAt"
],
"description": "Content added to a knowledge base: a file upload, website crawl, Sanity dataset, or inline text."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"delete": {
"operationId": "deleteImport",
"summary": "Delete an import",
"tags": ["imports"],
"description": "Deletes the import and every source it produced, and cancels its processing if it is still running. Use it to remove content you added by mistake.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "importId",
"required": true,
"description": "The import's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"204": {
"description": "The import and its sources were deleted.",
"content": {
"application/json": {
"schema": {
"type": "string",
"nullable": true,
"enum": [null],
"description": "The import and its sources were deleted."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/imports/{importId}/download": {
"get": {
"operationId": "downloadImport",
"summary": "Get a download URL for an import",
"tags": ["imports"],
"description": "Returns a short-lived signed URL that downloads the import's original content. Use the URL before `expiresAt`. Only file and text imports keep their original content. For crawl and dataset imports, the request returns `409` with code `importInvalidState`.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "importId",
"required": true,
"description": "The import's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A short-lived URL that downloads the import's original content.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "A signed URL that downloads the import's original content as a file."
},
"expiresAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When `url` expires, 10 minutes after the request."
}
},
"required": ["url", "expiresAt"],
"description": "A short-lived URL that downloads the import's original content."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/imports/uploads": {
"post": {
"operationId": "startUpload",
"summary": "Start a file upload",
"tags": ["imports"],
"description": "Creates a file import and returns a single-use signed upload URL that's valid for one hour. To finish the upload:\n\n1. Send the file in a `PUT` request to the upload URL.\n2. Call `POST .../imports/uploads/{importId}/complete` to start processing.\n\nIf you set `contentType`, the `PUT` request must send the same `Content-Type` header. If you omit it, the `PUT` request can send any `Content-Type` header or none. An import that isn't completed within 24 hours is deleted. Supports the `Idempotency-Key` header.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"minLength": 1,
"description": "The file's name."
},
"contentType": {
"description": "The file's MIME type. If you set it, the `PUT` upload must send the same `Content-Type` header.",
"type": "string",
"minLength": 1
}
},
"required": ["filename"]
}
}
}
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "header",
"name": "Idempotency-Key",
"required": false,
"description": "A unique value, such as a UUID, that makes retries safe. A retry with the same key and body returns the first response instead of repeating the work."
}
],
"responses": {
"201": {
"description": "The new file import and the URL to upload the file to.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"importId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The ID of the new import. Use it to complete the upload and track the import."
},
"uploadUrl": {
"type": "string",
"format": "uri",
"description": "A signed URL to send the file to in a single `PUT` request. It expires after one hour."
}
},
"required": ["importId", "uploadUrl"],
"description": "The new file import and the URL to upload the file to."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/imports/uploads/{importId}/complete": {
"post": {
"operationId": "completeUpload",
"summary": "Complete a file upload",
"tags": ["imports"],
"description": "Starts processing a file after you upload it to the signed URL from `POST .../imports/uploads`. Returns a job ID to poll.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"in": "path",
"name": "importId",
"required": true,
"description": "The import's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"202": {
"description": "A queued job that you can poll for progress.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The queued job's ID. Check its progress with `GET .../jobs/{jobId}`. Treat it as an opaque string. Its format can change."
}
},
"required": ["jobId"],
"description": "A queued job that you can poll for progress."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/jobs/{jobId}": {
"get": {
"operationId": "getJob",
"summary": "Get a job",
"tags": ["jobs"],
"description": "Returns the status of a background job, such as a build, import, or refresh. The endpoint that starts the work returns the job ID.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "jobId",
"required": true,
"description": "The job ID returned by the endpoint that started the work."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A background job, such as a build, an update or a sync, and its status. `kind` says which, and determines the shape of `result`.",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The job's ID. Treat it as an opaque string. Its format can change."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb…`) of the knowledge base the job belongs to."
},
"status": {
"type": "string",
"enum": [
"pending",
"queued",
"running",
"succeeded",
"failed",
"cancelled"
],
"description": "The job's status. `queued`: waiting for build capacity. `running`: in progress. `succeeded`: finished successfully. `failed`: stopped with an error. `cancelled`: stopped before it finished. `pending` isn't currently returned."
},
"startedAt": {
"nullable": true,
"description": "When the job started.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"completedAt": {
"nullable": true,
"description": "When the job finished. `null` while the job is queued or running.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"error": {
"description": "A readable reason the job failed or was cancelled. `null` for any other status.",
"nullable": true,
"type": "string"
},
"kind": {
"type": "string",
"enum": ["build"]
},
"result": {
"description": "The job's output. Only present when `status` is `succeeded`.",
"type": "object",
"properties": {
"revisionId": {
"type": "string",
"description": "The revision the build produced."
},
"status": {
"type": "string",
"enum": ["ready", "review"],
"description": "The knowledge base state after the build. `review`: the build filed critical issues that need triage."
},
"entryCount": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many entries the built outline has."
},
"issuesCreated": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many issues the build filed."
},
"criticalIssueCount": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many of those issues are critical."
}
},
"required": [
"revisionId",
"status",
"entryCount",
"issuesCreated",
"criticalIssueCount"
]
}
},
"required": [
"id",
"knowledgeBaseId",
"status",
"startedAt",
"completedAt",
"kind"
]
},
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The job's ID. Treat it as an opaque string. Its format can change."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb…`) of the knowledge base the job belongs to."
},
"status": {
"type": "string",
"enum": [
"pending",
"queued",
"running",
"succeeded",
"failed",
"cancelled"
],
"description": "The job's status. `queued`: waiting for build capacity. `running`: in progress. `succeeded`: finished successfully. `failed`: stopped with an error. `cancelled`: stopped before it finished. `pending` isn't currently returned."
},
"startedAt": {
"nullable": true,
"description": "When the job started.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"completedAt": {
"nullable": true,
"description": "When the job finished. `null` while the job is queued or running.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"error": {
"description": "A readable reason the job failed or was cancelled. `null` for any other status.",
"nullable": true,
"type": "string"
},
"kind": {
"type": "string",
"enum": ["update"]
},
"result": {
"description": "The job's output. Only present when `status` is `succeeded`.",
"type": "object",
"properties": {
"revisionId": {
"nullable": true,
"description": "The revision the update produced. `null` when no entry changed.",
"type": "string"
},
"entriesRewritten": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "How many entries were rewritten."
}
},
"required": ["revisionId", "entriesRewritten"]
}
},
"required": [
"id",
"knowledgeBaseId",
"status",
"startedAt",
"completedAt",
"kind"
]
},
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The job's ID. Treat it as an opaque string. Its format can change."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb…`) of the knowledge base the job belongs to."
},
"status": {
"type": "string",
"enum": [
"pending",
"queued",
"running",
"succeeded",
"failed",
"cancelled"
],
"description": "The job's status. `queued`: waiting for build capacity. `running`: in progress. `succeeded`: finished successfully. `failed`: stopped with an error. `cancelled`: stopped before it finished. `pending` isn't currently returned."
},
"startedAt": {
"nullable": true,
"description": "When the job started.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"completedAt": {
"nullable": true,
"description": "When the job finished. `null` while the job is queued or running.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"error": {
"description": "A readable reason the job failed or was cancelled. `null` for any other status.",
"nullable": true,
"type": "string"
},
"kind": {
"type": "string",
"enum": ["sync"]
}
},
"required": [
"id",
"knowledgeBaseId",
"status",
"startedAt",
"completedAt",
"kind"
]
}
],
"description": "A background job, such as a build, an update or a sync, and its status. `kind` says which, and determines the shape of `result`."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/issues/apply": {
"post": {
"operationId": "applyIssues",
"summary": "Accept and apply issues",
"tags": ["issues"],
"description": "Accepts the issues in `issueIds`, then queues a job that applies them, rewrites the affected entries, and saves a new revision. Returns a job ID. IDs of issues that no longer exist are skipped. Returns `409` with code `issueNotAutoApplicable`, and accepts none of the issues, if any of them cannot be applied: a `conflict` (resolve it with `POST .../issues/{issueId}/resolve`), or an `update_required` issue whose `scopePath` is `*` or names an entry that no longer exists. Dismiss those instead.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"issueIds": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"description": "The IDs of the issues to accept and apply."
}
},
"required": ["issueIds"]
}
}
}
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"202": {
"description": "A queued job that you can poll for progress.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"jobId": {
"type": "string",
"description": "The queued job's ID. Check its progress with `GET .../jobs/{jobId}`. Treat it as an opaque string. Its format can change."
}
},
"required": ["jobId"],
"description": "A queued job that you can poll for progress."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/issues/{issueId}/dismiss": {
"post": {
"operationId": "dismissIssue",
"summary": "Dismiss an issue",
"tags": ["issues"],
"description": "Marks the issue as rejected. If the issue already left triage, the request returns it unchanged. Returns `422` with code `issueDocumentInvalid` if the issue document was edited into a shape the API cannot verify. Returns `409` with code `issueTransitionConflict` if another change to the issue happened at the same time. You can safely retry a `409`.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "issueId",
"required": true,
"description": "The issue's document ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "An issue found in a knowledge base, and its triage status.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The issue's document ID. A later build that finds the same issue in unchanged sources reuses this ID, so your triage decision is kept."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb...`) of the knowledge base the issue belongs to."
},
"content": {
"oneOf": [
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["conflict"],
"description": "The issue type. `conflict` means two or more positions disagree on the same fact, and you choose which one is correct."
},
"claimKey": {
"type": "string",
"description": "A key naming the disputed fact, such as `free_tier.request_limit`. It never includes the disputed value, so every side shares it."
},
"context": {
"description": "One sentence that explains the question, when it needs one.",
"type": "string"
},
"sides": {
"minItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"claim": {
"type": "string",
"description": "The position as a self-contained sentence. This is the option you choose from."
},
"value": {
"description": "The disputed value on its own, such as `10,000/month`, without the sentence.",
"type": "string"
},
"entryPaths": {
"description": "Paths of the entries that state this position.",
"type": "array",
"items": {
"type": "string"
}
},
"sourceIds": {
"description": "IDs of the sources that directly back this position.",
"type": "array",
"items": {
"type": "string"
}
},
"where": {
"description": "The documents that state this value, by the names you know them by.",
"type": "string"
},
"citations": {
"description": "Quotes from the documents that state this value, copied word for word and checked against each document. A document whose wording could not be checked has none.",
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"pattern": "^[a-z2-7]{10}$",
"description": "Stable ID of this citation: 10 lowercase letters and digits. An entry body points to it with a `[^key]` marker."
},
"_type": {
"type": "string",
"enum": ["sanity.context.citation"]
},
"sourceId": {
"type": "string",
"description": "ID of the source document the quote comes from."
},
"title": {
"type": "string",
"description": "The source's name when it was quoted."
},
"url": {
"description": "Where the source lives on the web. Absent for uploaded files and datasets.",
"type": "string"
},
"quote": {
"type": "string",
"minLength": 1,
"maxLength": 300,
"description": "The passage from the source that backs the claims, copied word for word."
},
"prefix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just before the quote, to tell repeats apart."
},
"suffix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just after the quote, to tell repeats apart."
},
"lineStart": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "First line of the quote, counting from 1. Line numbers match `GET .../sources/{sourceId}/content`. A hint: the quote is the stable locator."
},
"lineEnd": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Last line of the quote, inclusive."
}
},
"required": [
"_key",
"_type",
"sourceId",
"title",
"quote",
"prefix",
"suffix",
"lineStart",
"lineEnd"
]
}
},
"authority": {
"description": "How much weight the sources behind this position carry. `primary`: your own content, such as uploaded files and pages on your own site. `secondary`: other sources. `community`: forums and Q&A sites.",
"type": "string",
"enum": ["primary", "secondary", "community"]
}
},
"required": ["claim"],
"description": "One position in a conflict, and the entries and sources it comes from."
},
"description": "The conflicting positions, at least two. To resolve the conflict, pass the index of one side as `resolution`."
},
"suggested": {
"description": "Index in `sides` of the suggested side, when there is one. It is only a hint: nothing is chosen until you resolve the issue.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"severity",
"scopePath",
"issue",
"suggestedFix",
"kind",
"claimKey",
"sides"
],
"description": "A conflict: two or more positions disagree on the same fact, and you choose which one is correct."
},
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["update_required"],
"description": "The issue type. `update_required` means an entry is out of date with its sources or contradicts an instruction, and needs a rewrite."
},
"citedSourceIds": {
"description": "IDs of the sources that led to the issue.",
"type": "array",
"items": {
"type": "string"
}
},
"claimKey": {
"description": "A key naming the specific finding, when the check that found it sets one.",
"type": "string"
},
"involvedScopes": {
"description": "Paths of the entries the issue involves, when it spans more than one entry.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["severity", "scopePath", "issue", "suggestedFix", "kind"],
"description": "An entry that needs a rewrite: it is out of date with its sources or contradicts an instruction."
}
],
"description": "What the issue found. The shape depends on `kind`."
},
"status": {
"type": "string",
"enum": ["open", "accepted", "rejected"],
"description": "The triage status. `open`: waiting for triage. `accepted`: accepted with `POST .../issues/apply`, or a conflict resolved to one side. `rejected`: dismissed. A rejected issue stays rejected. You can return an accepted conflict to `open` with `POST .../issues/{issueId}/reopen`."
},
"resolution": {
"nullable": true,
"description": "Index in `content.sides` of the side chosen when the conflict was resolved. For a conflict on a single entry, index `0` is the entry's current content. `null` until a conflict is resolved, and always `null` for other issue types.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"resolvedBy": {
"nullable": true,
"description": "Who triaged the issue, so you can review what your agents decided. `null` while the issue is open, or when the caller could not be identified.",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Sanity user ID of the person or robot that triaged the issue."
},
"kind": {
"type": "string",
"enum": ["user", "robot"],
"description": "`user` when a person made the decision. `robot` when a robot token did, such as an agent."
}
},
"required": ["id", "kind"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the issue was first filed."
},
"resolvedAt": {
"nullable": true,
"description": "When the issue left `open`. `null` while the issue is open.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"knowledgeBaseId",
"content",
"status",
"resolution",
"resolvedBy",
"createdAt",
"resolvedAt"
],
"description": "An issue found in a knowledge base, and its triage status."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/issues/{issueId}/resolve": {
"post": {
"operationId": "resolveIssue",
"summary": "Resolve a conflict issue",
"tags": ["issues"],
"description": "Resolves a conflict issue by choosing one of its sides. Set `resolution` to the index of a side in `content.sides`. For a conflict on a single entry, index `0` is the entry's current content, so choosing it keeps the entry as it is. Choosing any other side rewrites the entry, and the returned `jobId` tracks the rewrite. The decision becomes a standing instruction for every future build, and `resolvedBy` records who made it. To change a decision, resolve the accepted conflict again. Other issue types, dismissed conflicts, and out-of-range indexes return `422` with code `issueNotResolvable`.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"resolution": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "The index of the chosen side in the issue's `content.sides`."
}
},
"required": ["resolution"]
}
}
}
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "issueId",
"required": true,
"description": "The issue's document ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "The resolved issue, plus the job that rewrites the entry when the decision changes it.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"issue": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The issue's document ID. A later build that finds the same issue in unchanged sources reuses this ID, so your triage decision is kept."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb...`) of the knowledge base the issue belongs to."
},
"content": {
"oneOf": [
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["conflict"],
"description": "The issue type. `conflict` means two or more positions disagree on the same fact, and you choose which one is correct."
},
"claimKey": {
"type": "string",
"description": "A key naming the disputed fact, such as `free_tier.request_limit`. It never includes the disputed value, so every side shares it."
},
"context": {
"description": "One sentence that explains the question, when it needs one.",
"type": "string"
},
"sides": {
"minItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"claim": {
"type": "string",
"description": "The position as a self-contained sentence. This is the option you choose from."
},
"value": {
"description": "The disputed value on its own, such as `10,000/month`, without the sentence.",
"type": "string"
},
"entryPaths": {
"description": "Paths of the entries that state this position.",
"type": "array",
"items": {
"type": "string"
}
},
"sourceIds": {
"description": "IDs of the sources that directly back this position.",
"type": "array",
"items": {
"type": "string"
}
},
"where": {
"description": "The documents that state this value, by the names you know them by.",
"type": "string"
},
"citations": {
"description": "Quotes from the documents that state this value, copied word for word and checked against each document. A document whose wording could not be checked has none.",
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"pattern": "^[a-z2-7]{10}$",
"description": "Stable ID of this citation: 10 lowercase letters and digits. An entry body points to it with a `[^key]` marker."
},
"_type": {
"type": "string",
"enum": ["sanity.context.citation"]
},
"sourceId": {
"type": "string",
"description": "ID of the source document the quote comes from."
},
"title": {
"type": "string",
"description": "The source's name when it was quoted."
},
"url": {
"description": "Where the source lives on the web. Absent for uploaded files and datasets.",
"type": "string"
},
"quote": {
"type": "string",
"minLength": 1,
"maxLength": 300,
"description": "The passage from the source that backs the claims, copied word for word."
},
"prefix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just before the quote, to tell repeats apart."
},
"suffix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just after the quote, to tell repeats apart."
},
"lineStart": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "First line of the quote, counting from 1. Line numbers match `GET .../sources/{sourceId}/content`. A hint: the quote is the stable locator."
},
"lineEnd": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Last line of the quote, inclusive."
}
},
"required": [
"_key",
"_type",
"sourceId",
"title",
"quote",
"prefix",
"suffix",
"lineStart",
"lineEnd"
]
}
},
"authority": {
"description": "How much weight the sources behind this position carry. `primary`: your own content, such as uploaded files and pages on your own site. `secondary`: other sources. `community`: forums and Q&A sites.",
"type": "string",
"enum": ["primary", "secondary", "community"]
}
},
"required": ["claim"],
"description": "One position in a conflict, and the entries and sources it comes from."
},
"description": "The conflicting positions, at least two. To resolve the conflict, pass the index of one side as `resolution`."
},
"suggested": {
"description": "Index in `sides` of the suggested side, when there is one. It is only a hint: nothing is chosen until you resolve the issue.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"severity",
"scopePath",
"issue",
"suggestedFix",
"kind",
"claimKey",
"sides"
],
"description": "A conflict: two or more positions disagree on the same fact, and you choose which one is correct."
},
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["update_required"],
"description": "The issue type. `update_required` means an entry is out of date with its sources or contradicts an instruction, and needs a rewrite."
},
"citedSourceIds": {
"description": "IDs of the sources that led to the issue.",
"type": "array",
"items": {
"type": "string"
}
},
"claimKey": {
"description": "A key naming the specific finding, when the check that found it sets one.",
"type": "string"
},
"involvedScopes": {
"description": "Paths of the entries the issue involves, when it spans more than one entry.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"severity",
"scopePath",
"issue",
"suggestedFix",
"kind"
],
"description": "An entry that needs a rewrite: it is out of date with its sources or contradicts an instruction."
}
],
"description": "What the issue found. The shape depends on `kind`."
},
"status": {
"type": "string",
"enum": ["open", "accepted", "rejected"],
"description": "The triage status. `open`: waiting for triage. `accepted`: accepted with `POST .../issues/apply`, or a conflict resolved to one side. `rejected`: dismissed. A rejected issue stays rejected. You can return an accepted conflict to `open` with `POST .../issues/{issueId}/reopen`."
},
"resolution": {
"nullable": true,
"description": "Index in `content.sides` of the side chosen when the conflict was resolved. For a conflict on a single entry, index `0` is the entry's current content. `null` until a conflict is resolved, and always `null` for other issue types.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"resolvedBy": {
"nullable": true,
"description": "Who triaged the issue, so you can review what your agents decided. `null` while the issue is open, or when the caller could not be identified.",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Sanity user ID of the person or robot that triaged the issue."
},
"kind": {
"type": "string",
"enum": ["user", "robot"],
"description": "`user` when a person made the decision. `robot` when a robot token did, such as an agent."
}
},
"required": ["id", "kind"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the issue was first filed."
},
"resolvedAt": {
"nullable": true,
"description": "When the issue left `open`. `null` while the issue is open.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"knowledgeBaseId",
"content",
"status",
"resolution",
"resolvedBy",
"createdAt",
"resolvedAt"
],
"description": "The resolved conflict issue, now `accepted`."
},
"jobId": {
"nullable": true,
"description": "ID of the job that rewrites the entry to match the chosen side. Poll it with `GET .../jobs/{jobId}`. `null` when nothing is rewritten: you chose index `0`, or the conflict applies to the whole knowledge base.",
"type": "string"
}
},
"required": ["issue", "jobId"],
"description": "The resolved issue, plus the job that rewrites the entry when the decision changes it."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/issues/{issueId}/reopen": {
"post": {
"operationId": "reopenIssue",
"summary": "Reopen an accepted conflict",
"tags": ["issues"],
"description": "Returns an accepted conflict issue to triage, clears its resolution, and deletes the instruction the resolution created. Reopening an open or dismissed conflict returns it unchanged. Other issue types return `422` with code `issueNotResolvable`.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "issueId",
"required": true,
"description": "The issue's document ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "An issue found in a knowledge base, and its triage status.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The issue's document ID. A later build that finds the same issue in unchanged sources reuses this ID, so your triage decision is kept."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb...`) of the knowledge base the issue belongs to."
},
"content": {
"oneOf": [
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["conflict"],
"description": "The issue type. `conflict` means two or more positions disagree on the same fact, and you choose which one is correct."
},
"claimKey": {
"type": "string",
"description": "A key naming the disputed fact, such as `free_tier.request_limit`. It never includes the disputed value, so every side shares it."
},
"context": {
"description": "One sentence that explains the question, when it needs one.",
"type": "string"
},
"sides": {
"minItems": 2,
"type": "array",
"items": {
"type": "object",
"properties": {
"claim": {
"type": "string",
"description": "The position as a self-contained sentence. This is the option you choose from."
},
"value": {
"description": "The disputed value on its own, such as `10,000/month`, without the sentence.",
"type": "string"
},
"entryPaths": {
"description": "Paths of the entries that state this position.",
"type": "array",
"items": {
"type": "string"
}
},
"sourceIds": {
"description": "IDs of the sources that directly back this position.",
"type": "array",
"items": {
"type": "string"
}
},
"where": {
"description": "The documents that state this value, by the names you know them by.",
"type": "string"
},
"citations": {
"description": "Quotes from the documents that state this value, copied word for word and checked against each document. A document whose wording could not be checked has none.",
"type": "array",
"items": {
"type": "object",
"properties": {
"_key": {
"type": "string",
"pattern": "^[a-z2-7]{10}$",
"description": "Stable ID of this citation: 10 lowercase letters and digits. An entry body points to it with a `[^key]` marker."
},
"_type": {
"type": "string",
"enum": ["sanity.context.citation"]
},
"sourceId": {
"type": "string",
"description": "ID of the source document the quote comes from."
},
"title": {
"type": "string",
"description": "The source's name when it was quoted."
},
"url": {
"description": "Where the source lives on the web. Absent for uploaded files and datasets.",
"type": "string"
},
"quote": {
"type": "string",
"minLength": 1,
"maxLength": 300,
"description": "The passage from the source that backs the claims, copied word for word."
},
"prefix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just before the quote, to tell repeats apart."
},
"suffix": {
"type": "string",
"maxLength": 32,
"description": "Up to 32 characters of source text just after the quote, to tell repeats apart."
},
"lineStart": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "First line of the quote, counting from 1. Line numbers match `GET .../sources/{sourceId}/content`. A hint: the quote is the stable locator."
},
"lineEnd": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Last line of the quote, inclusive."
}
},
"required": [
"_key",
"_type",
"sourceId",
"title",
"quote",
"prefix",
"suffix",
"lineStart",
"lineEnd"
]
}
},
"authority": {
"description": "How much weight the sources behind this position carry. `primary`: your own content, such as uploaded files and pages on your own site. `secondary`: other sources. `community`: forums and Q&A sites.",
"type": "string",
"enum": ["primary", "secondary", "community"]
}
},
"required": ["claim"],
"description": "One position in a conflict, and the entries and sources it comes from."
},
"description": "The conflicting positions, at least two. To resolve the conflict, pass the index of one side as `resolution`."
},
"suggested": {
"description": "Index in `sides` of the suggested side, when there is one. It is only a hint: nothing is chosen until you resolve the issue.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"severity",
"scopePath",
"issue",
"suggestedFix",
"kind",
"claimKey",
"sides"
],
"description": "A conflict: two or more positions disagree on the same fact, and you choose which one is correct."
},
{
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "suggestion"],
"description": "How serious the issue is. `critical`: content is wrong or missing in a way that can mislead an agent. `suggestion`: a change that improves quality."
},
"scopePath": {
"type": "string",
"description": "Path of the entry the issue is about, or `*` when it applies to the whole knowledge base."
},
"issue": {
"type": "string",
"description": "What the problem is, in one or two sentences."
},
"suggestedFix": {
"type": "string",
"description": "What to do to fix the issue."
},
"kind": {
"type": "string",
"enum": ["update_required"],
"description": "The issue type. `update_required` means an entry is out of date with its sources or contradicts an instruction, and needs a rewrite."
},
"citedSourceIds": {
"description": "IDs of the sources that led to the issue.",
"type": "array",
"items": {
"type": "string"
}
},
"claimKey": {
"description": "A key naming the specific finding, when the check that found it sets one.",
"type": "string"
},
"involvedScopes": {
"description": "Paths of the entries the issue involves, when it spans more than one entry.",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["severity", "scopePath", "issue", "suggestedFix", "kind"],
"description": "An entry that needs a rewrite: it is out of date with its sources or contradicts an instruction."
}
],
"description": "What the issue found. The shape depends on `kind`."
},
"status": {
"type": "string",
"enum": ["open", "accepted", "rejected"],
"description": "The triage status. `open`: waiting for triage. `accepted`: accepted with `POST .../issues/apply`, or a conflict resolved to one side. `rejected`: dismissed. A rejected issue stays rejected. You can return an accepted conflict to `open` with `POST .../issues/{issueId}/reopen`."
},
"resolution": {
"nullable": true,
"description": "Index in `content.sides` of the side chosen when the conflict was resolved. For a conflict on a single entry, index `0` is the entry's current content. `null` until a conflict is resolved, and always `null` for other issue types.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"resolvedBy": {
"nullable": true,
"description": "Who triaged the issue, so you can review what your agents decided. `null` while the issue is open, or when the caller could not be identified.",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Sanity user ID of the person or robot that triaged the issue."
},
"kind": {
"type": "string",
"enum": ["user", "robot"],
"description": "`user` when a person made the decision. `robot` when a robot token did, such as an agent."
}
},
"required": ["id", "kind"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the issue was first filed."
},
"resolvedAt": {
"nullable": true,
"description": "When the issue left `open`. `null` while the issue is open.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"knowledgeBaseId",
"content",
"status",
"resolution",
"resolvedBy",
"createdAt",
"resolvedAt"
],
"description": "An issue found in a knowledge base, and its triage status."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/instructions": {
"post": {
"operationId": "createInstruction",
"summary": "Create an instruction",
"tags": ["instructions"],
"description": "Creates a standing instruction for how entries that cite its sources are written. Every instruction applies to specific sources, set in `scopeSourceIds`. To rebuild entries under the new instruction right away, pass their paths in `rebuildPaths`. The response includes the rebuild job ID, or `null` if the rebuild could not start. The instruction is saved either way. After the instruction is saved, a background check files issues for entries that contradict it. If you already checked the instruction for contradictions, set `verified` to skip the background check. If the requested rebuild does not start, the background check runs even when `verified` is set.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"statement": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "The instruction in plain language. Builds follow it over what the sources say."
},
"scopeSourceIds": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"description": "IDs of the sources the instruction applies to. Builds apply it when they write entries built from these sources. IDs of sources that no longer exist are dropped. If none exist, the request returns `422` with code `instructionScopeVanished`."
},
"rebuildPaths": {
"description": "Paths of entries to rebuild under the new instruction right away. The response returns the rebuild job ID in `rebuildJobId`.",
"minItems": 1,
"maxItems": 200,
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"verified": {
"description": "Whether you already checked the instruction for entries that contradict it. When `true`, the background check that files issues for those entries is skipped. It still runs if the rebuild you requested in `rebuildPaths` does not start.",
"type": "boolean"
}
},
"required": ["statement", "scopeSourceIds"],
"description": "The instruction to create, and any entries to rebuild under it."
}
}
},
"description": "The instruction to create, and any entries to rebuild under it."
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"201": {
"description": "The created instruction, and the rebuild it started.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"instruction": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The instruction's document ID."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb...`) of the knowledge base the instruction belongs to."
},
"origin": {
"type": "string",
"enum": ["conflict", "human"],
"description": "How the instruction was created. `human`: someone wrote it. `conflict`: it records the side chosen when a conflict issue was resolved. Both kinds work the same way in builds."
},
"status": {
"type": "string",
"enum": ["active", "archived"],
"description": "Whether builds apply the instruction. `active`: builds apply it. `archived`: a refresh found that its sources no longer support it, so builds stop applying it. To reactivate an archived instruction, update it."
},
"statement": {
"type": "string",
"description": "The instruction in plain language. Builds follow it over what the sources say."
},
"scopeSourceIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"description": "IDs of the sources the instruction applies to. Builds apply it when they write entries built from these sources. An empty array means all of its sources were removed, so it applies to no entries."
},
"archivedAt": {
"nullable": true,
"description": "When a refresh archived the instruction. `null` while it is active.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"archivedReason": {
"nullable": true,
"description": "Why the instruction was archived. `null` while it is active.",
"type": "string"
},
"sourceIssueId": {
"nullable": true,
"description": "ID of the conflict issue this instruction records. `null` when `origin` is `human`.",
"type": "string"
},
"createdBy": {
"nullable": true,
"description": "Who created the instruction. `null` for instructions created by resolving a conflict, and when the creator is unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"updatedBy": {
"nullable": true,
"description": "Who last updated the instruction through the API. `null` when it was never updated, or when the person is unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the instruction was created."
},
"updatedAt": {
"nullable": true,
"description": "When the instruction last changed, including changes a refresh makes. `null` when the time is unknown.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"knowledgeBaseId",
"origin",
"status",
"statement",
"scopeSourceIds",
"archivedAt",
"archivedReason",
"sourceIssueId",
"createdBy",
"updatedBy",
"createdAt",
"updatedAt"
],
"description": "The created instruction."
},
"rebuildJobId": {
"nullable": true,
"description": "ID of the job that rebuilds the entries in `rebuildPaths`. Poll it with `GET .../jobs/{jobId}`. `null` when you didn't pass `rebuildPaths` or the rebuild could not start. The instruction is saved either way.",
"type": "string"
}
},
"required": ["instruction", "rebuildJobId"],
"description": "The created instruction, and the rebuild it started."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/knowledge-bases/{knowledgeBaseId}/instructions/{instructionId}": {
"patch": {
"operationId": "updateInstruction",
"summary": "Update an instruction",
"tags": ["instructions"],
"description": "Updates the instruction's statement or sources. The change applies from the next build. Any update also reactivates an archived instruction and ties it to the current content of its sources.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"statement": {
"description": "The new instruction text. Omit it to keep the current text.",
"type": "string",
"minLength": 1,
"maxLength": 2000
},
"scopeSourceIds": {
"description": "IDs of the sources the instruction applies to. Replaces the current list. Omit it to keep the current sources. IDs of sources that no longer exist are dropped. If none exist, the request returns `422` with code `instructionScopeVanished`.",
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
}
},
"description": "The changes to make to an instruction. Set `statement`, `scopeSourceIds`, or both. Any update also reactivates an archived instruction."
}
}
},
"description": "The changes to make to an instruction. Set `statement`, `scopeSourceIds`, or both. Any update also reactivates an archived instruction."
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "instructionId",
"required": true,
"description": "The instruction's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "A standing instruction that shapes how entries that cite its sources are written.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The instruction's document ID."
},
"knowledgeBaseId": {
"type": "string",
"description": "The ID (`kb...`) of the knowledge base the instruction belongs to."
},
"origin": {
"type": "string",
"enum": ["conflict", "human"],
"description": "How the instruction was created. `human`: someone wrote it. `conflict`: it records the side chosen when a conflict issue was resolved. Both kinds work the same way in builds."
},
"status": {
"type": "string",
"enum": ["active", "archived"],
"description": "Whether builds apply the instruction. `active`: builds apply it. `archived`: a refresh found that its sources no longer support it, so builds stop applying it. To reactivate an archived instruction, update it."
},
"statement": {
"type": "string",
"description": "The instruction in plain language. Builds follow it over what the sources say."
},
"scopeSourceIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"description": "IDs of the sources the instruction applies to. Builds apply it when they write entries built from these sources. An empty array means all of its sources were removed, so it applies to no entries."
},
"archivedAt": {
"nullable": true,
"description": "When a refresh archived the instruction. `null` while it is active.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"archivedReason": {
"nullable": true,
"description": "Why the instruction was archived. `null` while it is active.",
"type": "string"
},
"sourceIssueId": {
"nullable": true,
"description": "ID of the conflict issue this instruction records. `null` when `origin` is `human`.",
"type": "string"
},
"createdBy": {
"nullable": true,
"description": "Who created the instruction. `null` for instructions created by resolving a conflict, and when the creator is unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"updatedBy": {
"nullable": true,
"description": "Who last updated the instruction through the API. `null` when it was never updated, or when the person is unknown.",
"type": "object",
"properties": {
"id": {
"nullable": true,
"description": "The Sanity user ID, or `sanity-system` when Sanity Context made the change. `null` if unknown.",
"type": "string"
},
"displayName": {
"nullable": true,
"description": "The user's name when the action happened. `null` if unknown. For the current name, look up the user by `id`.",
"type": "string"
}
},
"required": ["id", "displayName"]
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the instruction was created."
},
"updatedAt": {
"nullable": true,
"description": "When the instruction last changed, including changes a refresh makes. `null` when the time is unknown.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"id",
"knowledgeBaseId",
"origin",
"status",
"statement",
"scopeSourceIds",
"archivedAt",
"archivedReason",
"sourceIssueId",
"createdBy",
"updatedBy",
"createdAt",
"updatedAt"
],
"description": "A standing instruction that shapes how entries that cite its sources are written."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"delete": {
"operationId": "deleteInstruction",
"summary": "Delete an instruction",
"tags": ["instructions"],
"description": "Deletes the instruction. Builds stop applying it from the next run. Entries already written under it keep their text until they are rebuilt; pass `rebuild=true` to rebuild every entry that cites its sources right away.",
"parameters": [
{
"schema": {
"type": "string",
"enum": ["true", "false"]
},
"in": "query",
"name": "rebuild",
"required": false,
"description": "Set to `true` to rebuild every entry that cites the instruction's sources once it is deleted, so pages written under the instruction reflect their sources again. The response returns the rebuild job ID in `rebuildJobId`."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "knowledgeBaseId",
"required": true,
"description": "The knowledge base's ID (`kb...`), its `publicId`. Its UUID `id` is also accepted."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "instructionId",
"required": true,
"description": "The instruction's ID."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
}
],
"responses": {
"200": {
"description": "The rebuild the delete started, if any.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"rebuildJobId": {
"nullable": true,
"description": "ID of the job that rebuilds the entries citing the instruction's sources. Poll it with `GET .../jobs/{jobId}`. `null` when you didn't pass `rebuild=true`, no entry cites those sources, or the rebuild could not start. The instruction is deleted either way.",
"type": "string"
}
},
"required": ["rebuildJobId"],
"description": "The rebuild the delete started, if any."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/organizations/{organizationId}/mcp": {
"post": {
"operationId": "createMcpEndpoint",
"summary": "Create an MCP endpoint",
"tags": ["mcp"],
"description": "Creates an MCP endpoint with a title, a name, and at least one source. A source is a knowledge base, identified by its ID (`kb…`), or a dataset, identified as `<projectId>.<datasetName>`. An endpoint can serve any number of knowledge bases and at most one dataset, all at once. A GROQ filter is only kept when the endpoint has a dataset. The name must be unique in your organization, and you can't change it later. Duplicate sources with the same `type` and `id` are combined. The response includes the `url` agents connect to. To list or inspect endpoints, query `sanity.context.mcp` documents with GROQ from your organization's document store. Requires the `sanity.context.mcp.create` grant on the organization, which the Administrator and Developer roles have. Adding a dataset also requires full read access to the dataset and, on its project, the Administrator or Developer role or a custom role that can create datasets.\n\nA taken name returns `409` with code `mcpEndpointNameConflict`. A knowledge base that doesn't exist in the organization returns `422` with code `mcpSourceKnowledgeBaseNotFound`, and an invalid GROQ filter returns `422` with code `invalidGroqFilter`.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "The endpoint's display title, up to 100 characters."
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"description": "The endpoint's name, used in its URL. Lowercase letters, digits and single hyphens, up to 64 characters, unique in the organization. It can't be changed after the endpoint is created. `by-name` and names shaped like an endpoint ID are reserved."
},
"sources": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["knowledge-base"],
"description": "The source type. `knowledge-base` serves a whole knowledge base."
},
"id": {
"type": "string",
"minLength": 1,
"description": "The knowledge base ID (`kb…`)."
}
},
"required": ["type", "id"]
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["dataset"],
"description": "The source type. `dataset` serves documents from a Sanity dataset, limited by the MCP endpoint's `groqFilter` when set."
},
"id": {
"type": "string",
"pattern": "^[a-z0-9]+\\.[a-z0-9][a-z0-9_-]*$",
"description": "The dataset, as `<projectId>.<datasetName>`."
},
"workspace": {
"default": null,
"description": "The studio workspace whose schema agents use, by name. `null` uses the studio's first workspace.",
"nullable": true,
"type": "string",
"minLength": 1
},
"perspective": {
"default": null,
"description": "The perspective agents query the dataset with: `published`, `drafts`, or `raw`. `null` uses `published`.",
"nullable": true,
"type": "string",
"enum": ["published", "drafts", "raw", null]
},
"semanticSearch": {
"default": null,
"description": "Whether agents can use semantic search on the dataset. `false` turns it off. `true` or `null` use it while the dataset has embeddings enabled and the organization has embeddings usage left.",
"nullable": true,
"type": "boolean"
}
},
"required": ["type", "id"]
}
],
"description": "A content source that an MCP endpoint serves: a knowledge base or a Sanity dataset."
},
"description": "The content the endpoint serves: 1 to 100 sources, any number of knowledge bases and at most one dataset, served together. Order has no meaning."
},
"instructions": {
"type": "string",
"minLength": 1,
"maxLength": 10000,
"description": "Instructions for connecting agents, up to 10,000 characters."
},
"groqFilter": {
"type": "string",
"minLength": 1,
"maxLength": 10000,
"description": "A GROQ filter that limits which documents the endpoint's dataset source serves, such as `_type in [\"post\", \"author\"]`. Knowledge base sources aren't filtered. Kept only while the endpoint has a dataset source."
}
},
"required": ["title", "name", "sources"],
"description": "CreateMcpEndpointInput"
}
}
},
"description": "CreateMcpEndpointInput"
},
"parameters": [
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"201": {
"description": "McpEndpoint",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The endpoint's ID (`mcp…`). Update and delete accept it or the endpoint's name."
},
"organizationId": {
"type": "string",
"description": "The ID of the organization that owns the endpoint."
},
"title": {
"type": "string",
"description": "The endpoint's display title."
},
"name": {
"type": "string",
"description": "The endpoint's name, used in its URL. It can't be changed."
},
"sources": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["knowledge-base"],
"description": "The source type. `knowledge-base` serves a whole knowledge base."
},
"id": {
"type": "string",
"minLength": 1,
"description": "The knowledge base ID (`kb…`)."
}
},
"required": ["type", "id"]
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["dataset"],
"description": "The source type. `dataset` serves documents from a Sanity dataset, limited by the MCP endpoint's `groqFilter` when set."
},
"id": {
"type": "string",
"pattern": "^[a-z0-9]+\\.[a-z0-9][a-z0-9_-]*$",
"description": "The dataset, as `<projectId>.<datasetName>`."
},
"workspace": {
"default": null,
"description": "The studio workspace whose schema agents use, by name. `null` uses the studio's first workspace.",
"nullable": true,
"type": "string",
"minLength": 1
},
"perspective": {
"default": null,
"description": "The perspective agents query the dataset with: `published`, `drafts`, or `raw`. `null` uses `published`.",
"nullable": true,
"type": "string",
"enum": ["published", "drafts", "raw", null]
},
"semanticSearch": {
"default": null,
"description": "Whether agents can use semantic search on the dataset. `false` turns it off. `true` or `null` use it while the dataset has embeddings enabled and the organization has embeddings usage left.",
"nullable": true,
"type": "boolean"
}
},
"required": ["type", "id", "workspace", "perspective", "semanticSearch"]
}
],
"description": "A content source that an MCP endpoint serves: a knowledge base or a Sanity dataset."
},
"description": "The content the endpoint serves: any number of knowledge bases and at most one dataset, served together."
},
"instructions": {
"nullable": true,
"description": "Instructions for connecting agents, or `null` if none are set.",
"type": "string"
},
"groqFilter": {
"nullable": true,
"description": "The GROQ filter that limits the endpoint's dataset source, or `null` if none is set or the endpoint has no dataset.",
"type": "string"
},
"url": {
"type": "string",
"format": "uri",
"description": "The URL agents connect to."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the endpoint was created, as an ISO 8601 timestamp."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the endpoint was last changed, as an ISO 8601 timestamp."
}
},
"required": [
"id",
"organizationId",
"title",
"name",
"sources",
"instructions",
"groqFilter",
"url",
"createdAt",
"updatedAt"
],
"description": "McpEndpoint"
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/organizations/{organizationId}/mcp/{mcpEndpoint}": {
"patch": {
"operationId": "updateMcpEndpoint",
"summary": "Update an MCP endpoint",
"tags": ["mcp"],
"description": "Updates the title, sources, instructions, or GROQ filter of the endpoint with that name or ID. To clear an optional field, set it to `null`. An endpoint can have at most one dataset source, and removing it clears the GROQ filter. You can't change the name, so the endpoint URL stays the same. Requires the `sanity.context.mcp.update` grant on the organization. Adding a dataset source requires full read access to the dataset and, on its project, the Administrator or Developer role or a custom role that can create datasets. Changing the GROQ filter requires the same access for the endpoint's dataset. Sending the current values changes nothing.\n\nAn unknown endpoint returns `404` with code `mcpEndpointNotFound`. A knowledge base that doesn't exist in the organization returns `422` with code `mcpSourceKnowledgeBaseNotFound`, and an invalid GROQ filter returns `422` with code `invalidGroqFilter`.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "The endpoint's display title, up to 100 characters."
},
"sources": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["knowledge-base"],
"description": "The source type. `knowledge-base` serves a whole knowledge base."
},
"id": {
"type": "string",
"minLength": 1,
"description": "The knowledge base ID (`kb…`)."
}
},
"required": ["type", "id"]
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["dataset"],
"description": "The source type. `dataset` serves documents from a Sanity dataset, limited by the MCP endpoint's `groqFilter` when set."
},
"id": {
"type": "string",
"pattern": "^[a-z0-9]+\\.[a-z0-9][a-z0-9_-]*$",
"description": "The dataset, as `<projectId>.<datasetName>`."
},
"workspace": {
"default": null,
"description": "The studio workspace whose schema agents use, by name. `null` uses the studio's first workspace.",
"nullable": true,
"type": "string",
"minLength": 1
},
"perspective": {
"default": null,
"description": "The perspective agents query the dataset with: `published`, `drafts`, or `raw`. `null` uses `published`.",
"nullable": true,
"type": "string",
"enum": ["published", "drafts", "raw", null]
},
"semanticSearch": {
"default": null,
"description": "Whether agents can use semantic search on the dataset. `false` turns it off. `true` or `null` use it while the dataset has embeddings enabled and the organization has embeddings usage left.",
"nullable": true,
"type": "boolean"
}
},
"required": ["type", "id"]
}
],
"description": "A content source that an MCP endpoint serves: a knowledge base or a Sanity dataset."
},
"description": "The content the endpoint serves: 1 to 100 sources, any number of knowledge bases and at most one dataset, served together. Order has no meaning."
},
"instructions": {
"description": "Instructions for connecting agents, up to 10,000 characters. `null` removes them.",
"nullable": true,
"type": "string",
"minLength": 1,
"maxLength": 10000
},
"groqFilter": {
"description": "A GROQ filter that limits the endpoint's dataset source. `null` removes it.",
"nullable": true,
"type": "string",
"minLength": 1,
"maxLength": 10000
}
},
"description": "UpdateMcpEndpointInput"
}
}
},
"description": "UpdateMcpEndpointInput"
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "mcpEndpoint",
"required": true,
"description": "The MCP endpoint's name, as in its URL, or its ID (`mcp…`). Names can't take the shape of an ID, so either one identifies the endpoint."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"200": {
"description": "McpEndpoint",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The endpoint's ID (`mcp…`). Update and delete accept it or the endpoint's name."
},
"organizationId": {
"type": "string",
"description": "The ID of the organization that owns the endpoint."
},
"title": {
"type": "string",
"description": "The endpoint's display title."
},
"name": {
"type": "string",
"description": "The endpoint's name, used in its URL. It can't be changed."
},
"sources": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["knowledge-base"],
"description": "The source type. `knowledge-base` serves a whole knowledge base."
},
"id": {
"type": "string",
"minLength": 1,
"description": "The knowledge base ID (`kb…`)."
}
},
"required": ["type", "id"]
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["dataset"],
"description": "The source type. `dataset` serves documents from a Sanity dataset, limited by the MCP endpoint's `groqFilter` when set."
},
"id": {
"type": "string",
"pattern": "^[a-z0-9]+\\.[a-z0-9][a-z0-9_-]*$",
"description": "The dataset, as `<projectId>.<datasetName>`."
},
"workspace": {
"default": null,
"description": "The studio workspace whose schema agents use, by name. `null` uses the studio's first workspace.",
"nullable": true,
"type": "string",
"minLength": 1
},
"perspective": {
"default": null,
"description": "The perspective agents query the dataset with: `published`, `drafts`, or `raw`. `null` uses `published`.",
"nullable": true,
"type": "string",
"enum": ["published", "drafts", "raw", null]
},
"semanticSearch": {
"default": null,
"description": "Whether agents can use semantic search on the dataset. `false` turns it off. `true` or `null` use it while the dataset has embeddings enabled and the organization has embeddings usage left.",
"nullable": true,
"type": "boolean"
}
},
"required": ["type", "id", "workspace", "perspective", "semanticSearch"]
}
],
"description": "A content source that an MCP endpoint serves: a knowledge base or a Sanity dataset."
},
"description": "The content the endpoint serves: any number of knowledge bases and at most one dataset, served together."
},
"instructions": {
"nullable": true,
"description": "Instructions for connecting agents, or `null` if none are set.",
"type": "string"
},
"groqFilter": {
"nullable": true,
"description": "The GROQ filter that limits the endpoint's dataset source, or `null` if none is set or the endpoint has no dataset.",
"type": "string"
},
"url": {
"type": "string",
"format": "uri",
"description": "The URL agents connect to."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the endpoint was created, as an ISO 8601 timestamp."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the endpoint was last changed, as an ISO 8601 timestamp."
}
},
"required": [
"id",
"organizationId",
"title",
"name",
"sources",
"instructions",
"groqFilter",
"url",
"createdAt",
"updatedAt"
],
"description": "McpEndpoint"
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"delete": {
"operationId": "deleteMcpEndpoint",
"summary": "Delete an MCP endpoint",
"tags": ["mcp"],
"description": "Deletes the MCP endpoint with that name or ID. Agents connected through it lose access, and its name can be used again. Requires the `sanity.context.mcp.delete` grant on the organization. An unknown endpoint returns `404` with code `mcpEndpointNotFound`.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "mcpEndpoint",
"required": true,
"description": "The MCP endpoint's name, as in its URL, or its ID (`mcp…`). Names can't take the shape of an ID, so either one identifies the endpoint."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"204": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "string",
"nullable": true,
"enum": [null]
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"post": {
"operationId": "serveMcpEndpoint",
"summary": "Connect to an MCP endpoint",
"tags": ["mcp"],
"description": "Receives Model Context Protocol (MCP) messages from agents over streamable HTTP (JSON-RPC 2.0). Agents send MCP messages in `POST` requests to this URL. `mcpEndpoint` is the permanent URL name of the endpoint. Errors are JSON-RPC error objects, not the standard error response.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "instructions",
"required": false,
"description": "Agent instructions that replace the endpoint's configured instructions for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "perspective",
"required": false,
"description": "The perspective for GROQ queries: `published` (default), `previewDrafts`, `raw`, or a release. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "embeddings",
"required": false,
"description": "Set to `true` or `false` to turn semantic search on or off. Omit it to use the dataset source setting. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "groqFilter",
"required": false,
"description": "A GROQ filter that narrows the endpoint's configured content filter for this request. Documents must match both. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string",
"enum": ["knowledge_base", "groq"]
},
"in": "query",
"name": "mode",
"required": false,
"description": "Serves only one side of the endpoint for this request: `knowledge_base` serves its knowledge bases and `groq` serves its dataset. Omit it to serve every source the endpoint has. A request whose chosen side the endpoint doesn't have is refused. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "knowledgeBases",
"required": false,
"description": "Comma-separated knowledge base public IDs (`kb...`) that replace the endpoint's knowledge base sources for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "linkResolver",
"required": false,
"description": "A JSON array that adds `_url` fields to query results. Each item has `types` (document types), `baseUrl`, and an optional `slugExpression`, a GROQ expression that defaults to `slug.current`. Invalid JSON is ignored."
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "workspace",
"required": false,
"description": "The studio workspace to use. Replaces the dataset source's workspace for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "mcpEndpoint",
"required": true,
"description": "The MCP endpoint's name, set when the endpoint was created."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"200": {
"description": "Default Response"
}
}
}
},
"/{apiVersion}/context/organizations/{organizationId}/mcp/{mcpEndpoint}/initial-context": {
"get": {
"operationId": "getMcpEndpointInitialContext",
"summary": "Get an MCP endpoint's initial context",
"tags": ["mcp"],
"description": "Returns the same text as the `initial_context` MCP tool, as plain text you can add to a system prompt. `heading_offset` shifts markdown headings down by that many levels. The default is `1`, so `#` becomes `##`.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "instructions",
"required": false,
"description": "Agent instructions that replace the endpoint's configured instructions for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "perspective",
"required": false,
"description": "The perspective for GROQ queries: `published` (default), `previewDrafts`, `raw`, or a release. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "embeddings",
"required": false,
"description": "Set to `true` or `false` to turn semantic search on or off. Omit it to use the dataset source setting. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "groqFilter",
"required": false,
"description": "A GROQ filter that narrows the endpoint's configured content filter for this request. Documents must match both. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string",
"enum": ["knowledge_base", "groq"]
},
"in": "query",
"name": "mode",
"required": false,
"description": "Serves only one side of the endpoint for this request: `knowledge_base` serves its knowledge bases and `groq` serves its dataset. Omit it to serve every source the endpoint has. A request whose chosen side the endpoint doesn't have is refused. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "knowledgeBases",
"required": false,
"description": "Comma-separated knowledge base public IDs (`kb...`) that replace the endpoint's knowledge base sources for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "linkResolver",
"required": false,
"description": "A JSON array that adds `_url` fields to query results. Each item has `types` (document types), `baseUrl`, and an optional `slugExpression`, a GROQ expression that defaults to `slug.current`. Invalid JSON is ignored."
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "workspace",
"required": false,
"description": "The studio workspace to use. Replaces the dataset source's workspace for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "heading_offset",
"required": false,
"description": "How many levels to shift markdown headings down, from `0` to `6`. Defaults to `1`, so `#` becomes `##`."
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "mcpEndpoint",
"required": true,
"description": "The MCP endpoint's name, set when the endpoint was created."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"200": {
"description": "Default Response"
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/organizations/{organizationId}/mcp/{mcpEndpoint}/status": {
"get": {
"operationId": "getMcpEndpointStatus",
"summary": "Check an MCP endpoint",
"tags": ["mcp"],
"description": "Checks whether an agent can connect to the endpoint with your credentials. A failed check returns `200` with that check's `ok` set to `false`, so you can see every problem at once. `requiredOk` summarizes the result. Returns `404` if the endpoint doesn't exist.",
"parameters": [
{
"schema": {
"type": "string"
},
"in": "query",
"name": "instructions",
"required": false,
"description": "Agent instructions that replace the endpoint's configured instructions for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "perspective",
"required": false,
"description": "The perspective for GROQ queries: `published` (default), `previewDrafts`, `raw`, or a release. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "embeddings",
"required": false,
"description": "Set to `true` or `false` to turn semantic search on or off. Omit it to use the dataset source setting. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "groqFilter",
"required": false,
"description": "A GROQ filter that narrows the endpoint's configured content filter for this request. Documents must match both. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string",
"enum": ["knowledge_base", "groq"]
},
"in": "query",
"name": "mode",
"required": false,
"description": "Serves only one side of the endpoint for this request: `knowledge_base` serves its knowledge bases and `groq` serves its dataset. Omit it to serve every source the endpoint has. A request whose chosen side the endpoint doesn't have is refused. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "knowledgeBases",
"required": false,
"description": "Comma-separated knowledge base public IDs (`kb...`) that replace the endpoint's knowledge base sources for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "linkResolver",
"required": false,
"description": "A JSON array that adds `_url` fields to query results. Each item has `types` (document types), `baseUrl`, and an optional `slugExpression`, a GROQ expression that defaults to `slug.current`. Invalid JSON is ignored."
},
{
"schema": {
"type": "string"
},
"in": "query",
"name": "workspace",
"required": false,
"description": "The studio workspace to use. Replaces the dataset source's workspace for this request. Deprecated: refused from API version `v2026-11-10`. Configure it on the MCP endpoint instead.",
"deprecated": true
},
{
"schema": {
"type": "string",
"minLength": 1
},
"in": "path",
"name": "mcpEndpoint",
"required": true,
"description": "The MCP endpoint's name, set when the endpoint was created."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"requiredOk": {
"type": "boolean",
"description": "Whether every check that applies to the connection passed, except `semanticSearch`. When `true`, an agent connecting with the same credentials can use the endpoint."
},
"checks": {
"type": "object",
"properties": {
"studio": {
"nullable": true,
"description": "Whether a deployed studio serves the endpoint's dataset. Its schema tells the agent which document types exist. `null` when the connection doesn't query a dataset.",
"anyOf": [
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [true],
"description": "The check passed."
},
"workspace": {
"type": "string",
"description": "The name of the studio workspace the connection uses."
},
"workspaceTitle": {
"type": "string",
"description": "The workspace's title."
},
"workspaceAutoSelected": {
"type": "boolean",
"description": "Whether the workspace was picked automatically because none was set. It is `false` when the dataset source's `workspace` chose it, or a `workspace` query parameter on versions before `v2026-11-10`."
},
"availableWorkspaces": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The workspace's name."
},
"title": {
"type": "string",
"description": "The workspace's title."
}
},
"required": ["name", "title"]
},
"description": "The deployed studio's workspaces for the endpoint's dataset."
}
},
"required": [
"ok",
"workspace",
"workspaceTitle",
"workspaceAutoSelected",
"availableWorkspaces"
]
},
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [false],
"description": "The check failed."
},
"error": {
"type": "string",
"description": "Why the check failed, written to show to users."
}
},
"required": ["ok", "error"]
}
]
},
"semanticSearch": {
"nullable": true,
"description": "Whether semantic search works on the endpoint's dataset. `null` when the connection doesn't query a dataset, or when semantic search is on but the dataset doesn't have embeddings enabled. It never affects `requiredOk`: without it, the agent searches with GROQ only.",
"anyOf": [
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [true],
"description": "The check passed."
},
"status": {
"nullable": true,
"description": "The dataset's embeddings index status, if known.",
"type": "string"
},
"withinUsageLimit": {
"nullable": true,
"description": "Whether the project is within its embeddings usage limit, or `null` if it couldn't be checked.",
"type": "boolean"
},
"active": {
"type": "boolean",
"description": "Whether agents connecting now can use semantic search. On versions before `v2026-11-10`, `?embeddings=true` forces the tool on for agents even when this is `false`."
},
"inactiveReason": {
"nullable": true,
"description": "Why semantic search isn't active: `turnedOff` when the dataset source has it off, `datasetEmbeddingsNotReady` while the dataset's embeddings are still being prepared, and `usageLimitReached` when the organization has no embeddings usage left. `null` when it is active.",
"type": "string",
"enum": [
"turnedOff",
"datasetEmbeddingsNotReady",
"usageLimitReached",
null
]
}
},
"required": [
"ok",
"status",
"withinUsageLimit",
"active",
"inactiveReason"
]
},
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [false],
"description": "The check failed."
},
"error": {
"type": "string",
"description": "Why the check failed, written to show to users."
}
},
"required": ["ok", "error"]
}
]
},
"schema": {
"nullable": true,
"description": "Whether the studio's schema has document types the agent can query. `null` when the connection doesn't query a dataset.",
"anyOf": [
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [true],
"description": "The check passed."
},
"documentTypes": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "The number of document types the agent can query, after the endpoint's GROQ filter."
},
"perspective": {
"type": "string",
"description": "The perspective agents query the dataset with, such as `published` or `drafts`."
}
},
"required": ["ok", "documentTypes", "perspective"]
},
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [false],
"description": "The check failed."
},
"error": {
"type": "string",
"description": "Why the check failed, written to show to users."
}
},
"required": ["ok", "error"]
}
]
},
"knowledgeBases": {
"nullable": true,
"description": "Whether every knowledge base the connection serves exists, is readable with your credentials, and has been built. `null` when the connection doesn't serve knowledge bases.",
"anyOf": [
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [true],
"description": "The check passed."
},
"resolved": {
"type": "array",
"items": {
"type": "string"
},
"description": "The IDs of the knowledge bases the connection serves."
}
},
"required": ["ok", "resolved"]
},
{
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"enum": [false],
"description": "The check failed."
},
"resolved": {
"type": "array",
"items": {
"type": "string"
},
"description": "The IDs of the knowledge bases that exist and that you can read."
},
"missing": {
"type": "array",
"items": {
"type": "string"
},
"description": "The IDs of knowledge bases that don't exist in the organization."
},
"denied": {
"type": "array",
"items": {
"type": "string"
},
"description": "The IDs of knowledge bases your credentials can't read."
},
"unbuilt": {
"type": "array",
"items": {
"type": "string"
},
"description": "The IDs of knowledge bases that haven't been built yet. Build them before connecting an agent."
},
"error": {
"type": "string",
"description": "Why the check failed, written to show to users."
}
},
"required": [
"ok",
"resolved",
"missing",
"denied",
"unbuilt",
"error"
]
}
]
}
},
"required": ["studio", "semanticSearch", "schema", "knowledgeBases"],
"description": "One result per check. A check is `null` when it doesn't apply to the connection."
}
},
"required": ["requiredOk", "checks"]
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
},
"/{apiVersion}/context/organizations/{organizationId}/conversations/{threadId}": {
"put": {
"operationId": "saveConversation",
"summary": "Record a conversation",
"tags": ["conversations"],
"description": "Creates or updates the recorded conversation for one thread. `threadId` identifies the conversation within your organization, so saving with the same `threadId` updates the same conversation. Requires Context Editor access or higher.\n\nEach save replaces the stored messages. `metadata`, `sharing`, and the model fields change only when you include them. `tokenUsage` is cumulative: send the usage for one generation call, and the API adds it to the conversation total. Usage is added only when the save changes the messages, so retries don't count it twice.\n\nTo report a failure, set `error` on the message where it happened: the tool result for a failed tool call, or the assistant message for a turn that failed instead of answering. The Insights dashboard highlights conversations with a failed turn and counts failed tool calls separately, because agents often recover from them.\n\nThe last write for a thread wins, so retries are safe. `sharing` records whether you share telemetry with Sanity: metrics only, or full transcripts.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"messages": {
"maxItems": 1000,
"type": "array",
"items": {
"type": "object",
"properties": {
"role": {
"type": "string",
"enum": ["user", "assistant", "system", "tool"],
"description": "Who sent the message. `user` is the person talking to the agent, `assistant` is the agent, `system` is a system prompt, and `tool` is a tool call or tool result."
},
"content": {
"default": null,
"description": "The message text. `null` when the message has no text, such as a tool call.",
"nullable": true,
"type": "string",
"maxLength": 20000
},
"toolName": {
"default": null,
"description": "The name of the tool for a `tool` message. `null` on other messages.",
"nullable": true,
"type": "string"
},
"toolType": {
"default": null,
"description": "The kind of `tool` message. `call` is the agent calling the tool, and `result` is what the tool returned. `null` on other messages.",
"nullable": true,
"type": "string",
"enum": ["call", "result", null]
},
"error": {
"default": null,
"description": "Why this step failed, including any stack trace. Set it on the tool result for a failed tool call, or on the assistant message for a turn that failed instead of answering. `null` when the step succeeded.",
"nullable": true,
"type": "string",
"maxLength": 20000
}
},
"required": ["role"],
"description": "One message in a conversation transcript."
},
"description": "The full transcript so far, in order. It replaces the stored messages."
},
"modelProvider": {
"description": "The provider of the model the agent used. When absent, the stored value stays unchanged.",
"type": "string"
},
"modelId": {
"description": "The ID of the model the agent used. When absent, the stored value stays unchanged.",
"type": "string"
},
"tokenUsage": {
"description": "Token usage for one generation call. The API adds it to the conversation total, but only when this save changes the messages.",
"type": "object",
"properties": {
"inputTokens": {
"description": "The number of input tokens.",
"type": "number"
},
"outputTokens": {
"description": "The number of output tokens.",
"type": "number"
},
"totalTokens": {
"description": "The total number of tokens.",
"type": "number"
}
}
},
"metadata": {
"description": "Up to 20 tags that describe the conversation. Well-known keys are `mcpEndpoints` (names of the MCP endpoints the conversation used), `app`, and `environment`. Add any other keys you need. Replaces the stored metadata. When absent, the stored value stays unchanged.",
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 256
},
{
"maxItems": 20,
"type": "array",
"items": {
"type": "string",
"maxLength": 256
}
}
]
}
},
"sharing": {
"description": "Your choice to share conversation telemetry with Sanity. Replaces the stored setting. When absent, the stored value stays unchanged.",
"type": "object",
"properties": {
"metrics": {
"description": "Whether to share classification metrics with Sanity: scores, sentiment, content gap counts, message counts and sizes, tool names, and model and token usage. Message content is not included.",
"type": "boolean"
},
"conversations": {
"description": "Whether to share full conversation transcripts with Sanity. When `true`, the API also sets `metrics` to `true`.",
"type": "boolean"
},
"contact": {
"description": "How the Sanity team can reach you about your agent, such as an email address or a Discord handle.",
"type": "string",
"maxLength": 200
}
}
}
},
"required": ["messages"],
"description": "A conversation transcript to save for one thread."
}
}
},
"description": "A conversation transcript to save for one thread."
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"in": "path",
"name": "threadId",
"required": true,
"description": "Your ID for the conversation thread, unique within your organization. Up to 200 characters."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"200": {
"description": "A recorded agent conversation: its transcript, metadata, token usage, and classification.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The conversation ID, unique within the organization. It matches the `_id` of the conversation document in your document store."
},
"threadId": {
"type": "string",
"description": "Your identifier for the conversation thread, unique within the organization. Saving with the same `threadId` updates the same conversation."
},
"metadata": {
"nullable": true,
"description": "Tags that describe the conversation, such as `mcpEndpoints`, `app`, and `environment`. Filter on them in GROQ queries. `null` until a save includes `metadata`.",
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 256
},
{
"maxItems": 20,
"type": "array",
"items": {
"type": "string",
"maxLength": 256
}
}
]
}
},
"startedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the API received the first save for this thread, as an ISO 8601 timestamp."
},
"messagesUpdatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the conversation was last saved, as an ISO 8601 timestamp."
},
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"role": {
"type": "string",
"enum": ["user", "assistant", "system", "tool"],
"description": "Who sent the message. `user` is the person talking to the agent, `assistant` is the agent, `system` is a system prompt, and `tool` is a tool call or tool result."
},
"content": {
"default": null,
"description": "The message text. `null` when the message has no text, such as a tool call.",
"nullable": true,
"type": "string",
"maxLength": 20000
},
"toolName": {
"default": null,
"description": "The name of the tool for a `tool` message. `null` on other messages.",
"nullable": true,
"type": "string"
},
"toolType": {
"default": null,
"description": "The kind of `tool` message. `call` is the agent calling the tool, and `result` is what the tool returned. `null` on other messages.",
"nullable": true,
"type": "string",
"enum": ["call", "result", null]
},
"error": {
"default": null,
"description": "Why this step failed, including any stack trace. Set it on the tool result for a failed tool call, or on the assistant message for a turn that failed instead of answering. `null` when the step succeeded.",
"nullable": true,
"type": "string",
"maxLength": 20000
},
"timestamp": {
"default": null,
"description": "When the API first received this message, as an ISO 8601 timestamp. The API sets it. Resending an unchanged message at the same position keeps its timestamp. `null` for messages recorded before timestamps existed.",
"nullable": true,
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"role",
"content",
"toolName",
"toolType",
"error",
"timestamp"
],
"description": "One message in a conversation transcript, with the time the API received it."
},
"description": "The conversation transcript, in order. Each save replaces it."
},
"modelProvider": {
"nullable": true,
"description": "The provider of the model the agent used. `null` until a save includes `modelProvider`.",
"type": "string"
},
"modelId": {
"nullable": true,
"description": "The ID of the model the agent used. `null` until a save includes `modelId`.",
"type": "string"
},
"tokenUsage": {
"nullable": true,
"description": "The running total of token usage for the conversation. `null` until a save includes `tokenUsage`.",
"type": "object",
"properties": {
"inputTokens": {
"description": "The number of input tokens.",
"type": "number"
},
"outputTokens": {
"description": "The number of output tokens.",
"type": "number"
},
"totalTokens": {
"description": "The total number of tokens.",
"type": "number"
}
}
},
"coreMetrics": {
"nullable": true,
"description": "The latest classification result. `null` until you record one.",
"type": "object",
"properties": {
"successScore": {
"description": "How well the agent resolved the user's needs, from 1 to 10.",
"type": "number"
},
"sentiment": {
"description": "The overall sentiment of the conversation.",
"type": "string",
"enum": ["positive", "neutral", "negative"]
},
"contentGaps": {
"description": "Topics the agent couldn't answer because it lacked content.",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"classifiedAt": {
"nullable": true,
"description": "When the latest classification result was recorded, as an ISO 8601 timestamp. The API sets it. `null` until you record a result.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"classificationError": {
"nullable": true,
"description": "Why your classifier couldn't classify the conversation. `null` when no failure is recorded. Recording a result clears it.",
"type": "string"
},
"sharing": {
"nullable": true,
"description": "Your choice to share conversation telemetry with Sanity. `null` until a save includes `sharing`.",
"type": "object",
"properties": {
"metrics": {
"description": "Whether to share classification metrics with Sanity: scores, sentiment, content gap counts, message counts and sizes, tool names, and model and token usage. Message content is not included.",
"type": "boolean"
},
"conversations": {
"description": "Whether to share full conversation transcripts with Sanity. When `true`, the API also sets `metrics` to `true`.",
"type": "boolean"
},
"contact": {
"description": "How the Sanity team can reach you about your agent, such as an email address or a Discord handle.",
"type": "string",
"maxLength": 200
}
}
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the conversation was created, as an ISO 8601 timestamp."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the conversation was last changed, as an ISO 8601 timestamp."
}
},
"required": [
"id",
"threadId",
"metadata",
"startedAt",
"messagesUpdatedAt",
"messages",
"modelProvider",
"modelId",
"tokenUsage",
"coreMetrics",
"classifiedAt",
"classificationError",
"sharing",
"createdAt",
"updatedAt"
],
"description": "A recorded agent conversation: its transcript, metadata, token usage, and classification."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"patch": {
"operationId": "classifyConversation",
"summary": "Record a conversation classification",
"tags": ["conversations"],
"description": "Records the classification your own model produced for one thread. Send exactly one of these fields:\n\n- `coreMetrics`: the classification result. The API sets `classifiedAt` and clears any recorded failure.\n- `classificationError`: why classification failed. Any earlier result stays unchanged.\n\nRequires the same access as recording a conversation. The last write wins, so a new classification replaces the previous one.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"coreMetrics": {
"description": "The classification result. The API sets `classifiedAt` and clears any recorded `classificationError`.",
"type": "object",
"properties": {
"successScore": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "How well the agent resolved the user's needs, as an integer from 1 to 10."
},
"sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative"],
"description": "The overall sentiment of the conversation."
},
"contentGaps": {
"maxItems": 50,
"type": "array",
"items": {
"type": "string",
"maxLength": 200
},
"description": "Topics the agent couldn't answer because it lacked content."
}
},
"required": ["successScore", "sentiment", "contentGaps"]
},
"classificationError": {
"description": "Why your classifier couldn't classify the conversation. Any earlier classification result stays unchanged.",
"type": "string",
"maxLength": 500
}
},
"description": "A classification result or failure for one conversation. Send exactly one of `coreMetrics` or `classificationError`."
}
}
},
"description": "A classification result or failure for one conversation. Send exactly one of `coreMetrics` or `classificationError`."
},
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"in": "path",
"name": "threadId",
"required": true,
"description": "Your ID for the conversation thread, unique within your organization. Up to 200 characters."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"200": {
"description": "A recorded agent conversation: its transcript, metadata, token usage, and classification.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The conversation ID, unique within the organization. It matches the `_id` of the conversation document in your document store."
},
"threadId": {
"type": "string",
"description": "Your identifier for the conversation thread, unique within the organization. Saving with the same `threadId` updates the same conversation."
},
"metadata": {
"nullable": true,
"description": "Tags that describe the conversation, such as `mcpEndpoints`, `app`, and `environment`. Filter on them in GROQ queries. `null` until a save includes `metadata`.",
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 256
},
{
"maxItems": 20,
"type": "array",
"items": {
"type": "string",
"maxLength": 256
}
}
]
}
},
"startedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the API received the first save for this thread, as an ISO 8601 timestamp."
},
"messagesUpdatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the conversation was last saved, as an ISO 8601 timestamp."
},
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"role": {
"type": "string",
"enum": ["user", "assistant", "system", "tool"],
"description": "Who sent the message. `user` is the person talking to the agent, `assistant` is the agent, `system` is a system prompt, and `tool` is a tool call or tool result."
},
"content": {
"default": null,
"description": "The message text. `null` when the message has no text, such as a tool call.",
"nullable": true,
"type": "string",
"maxLength": 20000
},
"toolName": {
"default": null,
"description": "The name of the tool for a `tool` message. `null` on other messages.",
"nullable": true,
"type": "string"
},
"toolType": {
"default": null,
"description": "The kind of `tool` message. `call` is the agent calling the tool, and `result` is what the tool returned. `null` on other messages.",
"nullable": true,
"type": "string",
"enum": ["call", "result", null]
},
"error": {
"default": null,
"description": "Why this step failed, including any stack trace. Set it on the tool result for a failed tool call, or on the assistant message for a turn that failed instead of answering. `null` when the step succeeded.",
"nullable": true,
"type": "string",
"maxLength": 20000
},
"timestamp": {
"default": null,
"description": "When the API first received this message, as an ISO 8601 timestamp. The API sets it. Resending an unchanged message at the same position keeps its timestamp. `null` for messages recorded before timestamps existed.",
"nullable": true,
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"role",
"content",
"toolName",
"toolType",
"error",
"timestamp"
],
"description": "One message in a conversation transcript, with the time the API received it."
},
"description": "The conversation transcript, in order. Each save replaces it."
},
"modelProvider": {
"nullable": true,
"description": "The provider of the model the agent used. `null` until a save includes `modelProvider`.",
"type": "string"
},
"modelId": {
"nullable": true,
"description": "The ID of the model the agent used. `null` until a save includes `modelId`.",
"type": "string"
},
"tokenUsage": {
"nullable": true,
"description": "The running total of token usage for the conversation. `null` until a save includes `tokenUsage`.",
"type": "object",
"properties": {
"inputTokens": {
"description": "The number of input tokens.",
"type": "number"
},
"outputTokens": {
"description": "The number of output tokens.",
"type": "number"
},
"totalTokens": {
"description": "The total number of tokens.",
"type": "number"
}
}
},
"coreMetrics": {
"nullable": true,
"description": "The latest classification result. `null` until you record one.",
"type": "object",
"properties": {
"successScore": {
"description": "How well the agent resolved the user's needs, from 1 to 10.",
"type": "number"
},
"sentiment": {
"description": "The overall sentiment of the conversation.",
"type": "string",
"enum": ["positive", "neutral", "negative"]
},
"contentGaps": {
"description": "Topics the agent couldn't answer because it lacked content.",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"classifiedAt": {
"nullable": true,
"description": "When the latest classification result was recorded, as an ISO 8601 timestamp. The API sets it. `null` until you record a result.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
"classificationError": {
"nullable": true,
"description": "Why your classifier couldn't classify the conversation. `null` when no failure is recorded. Recording a result clears it.",
"type": "string"
},
"sharing": {
"nullable": true,
"description": "Your choice to share conversation telemetry with Sanity. `null` until a save includes `sharing`.",
"type": "object",
"properties": {
"metrics": {
"description": "Whether to share classification metrics with Sanity: scores, sentiment, content gap counts, message counts and sizes, tool names, and model and token usage. Message content is not included.",
"type": "boolean"
},
"conversations": {
"description": "Whether to share full conversation transcripts with Sanity. When `true`, the API also sets `metrics` to `true`.",
"type": "boolean"
},
"contact": {
"description": "How the Sanity team can reach you about your agent, such as an email address or a Discord handle.",
"type": "string",
"maxLength": 200
}
}
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the conversation was created, as an ISO 8601 timestamp."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the conversation was last changed, as an ISO 8601 timestamp."
}
},
"required": [
"id",
"threadId",
"metadata",
"startedAt",
"messagesUpdatedAt",
"messages",
"modelProvider",
"modelId",
"tokenUsage",
"coreMetrics",
"classifiedAt",
"classificationError",
"sharing",
"createdAt",
"updatedAt"
],
"description": "A recorded agent conversation: its transcript, metadata, token usage, and classification."
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
},
"delete": {
"operationId": "deleteConversation",
"summary": "Delete a conversation",
"tags": ["conversations"],
"description": "Deletes the recorded conversation for one thread, including its messages and classification. Requires the same access as recording a conversation.\n\nSaving with the same `threadId` afterwards records a new conversation.",
"parameters": [
{
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"in": "path",
"name": "threadId",
"required": true,
"description": "Your ID for the conversation thread, unique within your organization. Up to 200 characters."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "apiVersion",
"required": true,
"description": "The API version: a date in the format `vYYYY-MM-DD`, for example `v2026-05-26`, or `vX` for the latest, unstable version."
},
{
"schema": {
"type": "string"
},
"in": "path",
"name": "organizationId",
"required": true,
"description": "The ID of the organization."
}
],
"responses": {
"204": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
"type": "string",
"nullable": true,
"enum": [null]
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApiErrorBody"
}
}
}
}
}
}
}
},
"servers": [
{
"url": "https://api.sanity.io",
"description": "Production"
}
],
"security": [
{
"bearerAuth": []
}
],
"tags": [
{
"name": "knowledge-bases",
"description": "Create, configure, and build knowledge bases."
},
{
"name": "entries",
"description": "Rebuild individual entries in a knowledge base."
},
{
"name": "issues",
"description": "Triage the issues that builds and refreshes find."
},
{
"name": "instructions",
"description": "Create standing instructions that steer every build."
},
{
"name": "mcp",
"description": "Connect agents to your knowledge bases through Model Context Protocol (MCP) endpoints."
},
{
"name": "conversations",
"description": "Record agent conversations and their classifications for Insights."
},
{
"name": "jobs",
"description": "Check the status of background jobs, such as builds, imports, and refreshes."
},
{
"name": "imports",
"description": "Add content to a knowledge base from file uploads, website crawls, Sanity datasets, and inline text."
},
{
"name": "sources",
"description": "Read the sources that imports produce and builds cite."
}
]
}