Content API

Fetching documents

Queries with parameters, direct document fetches, and the response envelope — including why a query should never be built by string concatenation.

A parameterised query

ts
const post = await client.fetch(
  `*[_type == "post" && slug.current == $slug][0]{
    title,
    publishedAt,
    "author": author->{name, bio},
    body
  }`,
  { slug },
)

Every value is a bound parameter. A GROQ query built by concatenation is the same class of mistake as SQL built by concatenation, and a slug arriving from a URL is exactly the untrusted input that makes it one.

Over HTTP directly

http
GET /api/v2026-07-26/data/query/production
  ?query=*%5B_type%20%3D%3D%20%22post%22%5D%7Btitle%7D
  &%24slug=%22hello%22
  &perspective=published

POST the same thing when the query is long enough to strain a URL:

bash
curl -X POST "$HOST/api/v2026-07-26/data/query/production" \
  -H 'content-type: application/json' \
  -d '{"query":"*[_type == $type][0...5]{title}","params":{"type":"post"}}'

One document by id

http
GET /api/v2026-07-26/data/doc/production/post-hello-new-orange

Returns { documents: [ … ] }. Useful when you already know the id; a query is the right tool for anything else.

The envelope

  • result — what the query evaluated to.
  • ms — server-side duration.
  • syncTags — the identifiers this result depends on. Use them as cache tags.
  • resultSourceMap — emitted when asked for, and used by preview overlays to map a rendered value back to the field it came from. Partial: not every projection shape is mapped yet.