Content API

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

bash
curl "https://your-project.vercel.app/api/v2026-07-26/data/query/production?query=count(*)"
json
{
  "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

FamilyPurpose
/data/query/:datasetGROQ, GET or POST, with params, perspectives and sync tags.
/data/doc/:dataset/:idFetch one document directly.
/data/mutate/:datasetCreate, patch and delete, applied as one transaction.
/data/actions/:datasetThe document actions the Studio uses: create, edit, publish, discard, delete, unpublish.
/data/listen/:datasetA 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/toWhat points at this document.
/assets/:kind/:datasetUploads, 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

ts
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.