The API, in one page
What is served, where, and what makes it Sanity-compatible: same routes, same request shapes, same response envelopes.
Everything is served under /api/:apiVersion/… from your own deployment. v2026-07-26 is the compatibility baseline — the version the behaviour is specified against — but any well-formed pinned version is accepted, because the Studio pins several different ones internally and a baseline-only rule would 404 half of it.
The shape of a request
curl "https://your-project.vercel.app/api/v2026-07-26/data/query/production?query=count(*)"{
"query": "count(*)",
"ms": 8,
"result": 42,
"syncTags": ["s1:ACG8JZ-274K_9k7VL6ibIA", "s1:F5M-wpjv05_iwsUfAdeUfQ"]
}The envelope is the Sanity one, including syncTags — the identifiers a client can use as cache tags, which is what makes exact invalidation possible.
The route families
| Family | Purpose |
|---|---|
/data/query/:dataset | GROQ, GET or POST, with params, perspectives and sync tags. |
/data/doc/:dataset/:id | Fetch one document directly. |
/data/mutate/:dataset | Create, patch and delete, applied as one transaction. |
/data/actions/:dataset | The document actions the Studio uses: create, edit, publish, discard, delete, unpublish. |
/data/listen/:dataset | A real server-sent-event stream of mutations. |
/data/history/:dataset/… | A document at a revision, its event list, and the transaction log. |
/data/references/:dataset/documents/:id/to | What points at this document. |
/assets/:kind/:dataset | Uploads, including a browser-direct path for large files. |
/images/…, /files/… | Byte delivery, with the supported transform parameters. |
There are also management-plane routes the Studio calls on boot — project and dataset metadata, grants, the user directory, key-value preferences — plus comments and tasks.
Connecting a client
import { createClient } from '@sanity/client'
export const client = createClient({
projectId: 'default',
dataset: 'production',
apiVersion: '2026-07-26',
useCdn: false,
apiHost: 'https://your-project.vercel.app',
})useCdn: false because there is no CDN in front of this API; caching is the frontend's job and the sync tags are how it does it well.
Anonymous access
An anonymous request gets the published perspective and nothing else. That is not a filter applied after the fact — without a session, the database connection cannot see draft rows at all. It is why the public site on this deployment can read with no credentials and still not leak unpublished work.
