APIs and SDKs

Content Release API Cheat Sheet

Query and modify Content Releases using the API

Interfacing with Content Releases is similar to interfacing with other documents and relationships in the Content Lake.

Prerequisites:

  • The examples below use a variety of APIs to cover common patterns. As releases aren't public, make sure your requests are authenticated and match the correct URL format for each API. For example, using Sanity clients or other integrations, you'll need to configure them with an appropriate token and permissions to view unpublished content.
  • Release APIs and features are available in API version 2025-02-19 and later unless otherwise noted.
  • Many query interactions on this page assume a perspective that can view release information. You should set the perspective to raw or a unique release stack when viewing release information.

Create a new release

As releases are Sanity documents, you can interact with them the same way you would any other document. The preferred method is with the Actions API.

Create the action:

// Example release create action
{
  "actionType": "sanity.action.release.create",
  // Exclude the _.releases. prefix from the releaseId
  "releaseId":"rEGM2JqQ3",
  "metadata": {
    "title": "Spring release",
    "description": "Changes involving the upcoming release",
    "releaseType": "undecided"
  }
}

Include the action in the <action> portion below:

Input

curl -X POST 'https://<project-id>.api.sanity.io/2025-02-19/data/actions/<dataset-name>' \
    -H 'Authorization: Bearer <token>' \
    -H 'Content-Type: application/json' \
    -D '{"actions":[<action>]}'

Example response

{
  "transactionId": "71GXGRT7Io3CmtCwpl6n8V"
}

The response is a transactionId. Learn more about transactions.

For a full list of available metadata properties, see the sanity.action.release.create reference documentation.

Modify release information

As releases are Sanity documents, you can interact with them the same way you would any other document. The preferred method is with the Actions API.

Create the action:

// Example release edit action
{
  "actionType": "sanity.action.release.edit",
  // Exclude the _.releases. prefix from the releaseId
  "releaseId":"rEGM2JqQ3",
  "patch": {
    "set": {
      "metadata": {        
        "title": "New release title"
      }
    }
  }
}

Include the action in the <action> portion below:

Input

curl -X POST 'https://<project-id>.api.sanity.io/2025-02-19/data/actions/<dataset-name>' \
    -H 'Authorization: Bearer <token>' \
    -H 'Content-Type: application/json' \
    -D '{"actions":[<action>]}'

Example response

{
  "transactionId": "71GXGRT7Io3CmtCwpl6n8V"
}

You can also edit releases using the Mutate API.

Get all releases for a project and dataset

Access releases by querying the documents with the releases::all() GROQ function. This is the preferred method for retrieving a list of releases.

JS Client

Use the client's fetch method to query for releases.

Input

import { createClient } from "@sanity/client";

const client = createClient({
    projectId: '<project-id>',
    dataset: '<dataset>',
    useCdn: true,
    apiVersion: '2025-02-19',
    token: '<token>',
    perspective: 'raw'
})

const query = "releases::all()"
const params = {}
client.fetch(query, params).then((data)=>{
  console.log(data)
})

Response

[
    {
      "_createdAt": "2024-11-26T21:30:57Z",
      "finalDocumentStates": null,
      "_updatedAt": "2024-12-17T16:33:26Z",
      "_type": "system.release",
      "name": "rHw6FBu82",
      "_id": "_.releases.rHw6FBu82",
      "state": "active",
      "metadata": {
        "releaseType": "scheduled",
        "title": "End of year release",
        "intendedPublishAt": "Mon Dec 30 2024"
      },
      "publishAt": "2024-12-30T08:00:00Z",
      "_rev": "JmI5JuFTDPq3paS6p09Jmu",
      "userId": "paATypsg4"
    },
    {
      "publishAt": null,
      "_rev": "1kbjGQwz5Z0FmijO2l7Lwl",
      "finalDocumentStates": [
        {
          "id": "versions.rglJO3Sfg.movie_70981",
          "_key": "1kbjGQwz5Z0FmijO2l7M0E"
        }
      ],
      "_id": "_.releases.rglJO3Sfg",
      "state": "published",
      "metadata": {
        "title": "Quick fixes",
        "releaseType": "asap"
      },
      "_createdAt": "2024-11-26T22:01:56Z",
      "_type": "system.release",
      "name": "rglJO3Sfg",
      "_updatedAt": "2024-12-02T17:32:59Z",
      "userId": ""
    },
    {
      "_createdAt": "2024-11-26T18:34:14Z",
      "name": "rqZSzJ1uS",
      "finalDocumentStates": [
        {
          "id": "versions.rqZSzJ1uS.movie_10681"
        }
      ],
      "userId": "paATypsg4",
      "_id": "_.releases.rqZSzJ1uS",
      "state": "published",
      "_updatedAt": "2024-12-05T17:22:00Z",
      "metadata": {
        "releaseType": "scheduled",
        "description": "Experimental updates for testing",
        "title": "Experimental updates",
        "intendedPublishAt": "2024-12-05T17:22:00.000Z"
      },
      "publishAt": "2024-12-05T17:22:00Z",
      "_rev": "5dKCVUpSDccCmU1E23aUAc",
      "_type": "system.release"
    },
  // ...
  ],

Query API

You access releases by querying for documents with the releases::all() GROQ function using the Query API. This is the preferred method for retrieving a list of releases.

Use the following GROQ query in the API request:

releases::all()

Input

curl "https://<project-id>.api.sanity.io/2025-02-19/data/query/<dataset-name>?query=<GROQ-QUERY>" \
    --H "Authorization: Bearer <token>" \

Example response

{
  "query": "*[releases::all()]",
  "result": [
    {
      "_createdAt": "2024-11-26T21:30:57Z",
      "finalDocumentStates": null,
      "_updatedAt": "2024-12-17T16:33:26Z",
      "_type": "system.release",
      "name": "rHw6FBu82",
      "_id": "_.releases.rHw6FBu82",
      "state": "active",
      "metadata": {
        "releaseType": "scheduled",
        "title": "End of year release",
        "intendedPublishAt": "Mon Dec 30 2024"
      },
      "publishAt": "2024-12-30T08:00:00Z",
      "_rev": "JmI5JuFTDPq3paS6p09Jmu",
      "userId": "paATypsg4"
    },
    {
      "publishAt": null,
      "_rev": "1kbjGQwz5Z0FmijO2l7Lwl",
      "finalDocumentStates": [
        {
          "id": "versions.rglJO3Sfg.movie_70981",
          "_key": "1kbjGQwz5Z0FmijO2l7M0E"
        }
      ],
      "_id": "_.releases.rglJO3Sfg",
      "state": "published",
      "metadata": {
        "title": "Quick fixes",
        "releaseType": "asap"
      },
      "_createdAt": "2024-11-26T22:01:56Z",
      "_type": "system.release",
      "name": "rglJO3Sfg",
      "_updatedAt": "2024-12-02T17:32:59Z",
      "userId": ""
    },
    {
      "_createdAt": "2024-11-26T18:34:14Z",
      "name": "rqZSzJ1uS",
      "finalDocumentStates": [
        {
          "id": "versions.rqZSzJ1uS.movie_10681"
        }
      ],
      "userId": "paATypsg4",
      "_id": "_.releases.rqZSzJ1uS",
      "state": "published",
      "_updatedAt": "2024-12-05T17:22:00Z",
      "metadata": {
        "releaseType": "scheduled",
        "description": "Experimental updates for testing",
        "title": "Experimental updates",
        "intendedPublishAt": "2024-12-05T17:22:00.000Z"
      },
      "publishAt": "2024-12-05T17:22:00Z",
      "_rev": "5dKCVUpSDccCmU1E23aUAc",
      "_type": "system.release"
    },
  ],
  "syncTags": [
    "s1:r6H+EQ"
  ],
  "ms": 3
}

To view only active releases, and exclude archived releases, adjust your GROQ query to compare the state property.

releases::all()[state == 'active']

Get all documents from a release

Query all documents associated with a release.

sanity::partOfRelease GROQ function

The sanity::partOfRelease GROQ function accepts a release name and returns all documents associated with the release.

Release ID vs. release name

Use the function in a GROQ query and pass the release name string.

import { createClient } from "@sanity/client";

const client = createClient({
    projectId: '<project-id>',
    dataset: '<dataset>',
    useCdn: false,
    apiVersion: '2025-02-19',
    token: '<token>',
    perspective: 'raw'
})

const query = "*[sanity::partOfRelease(<release-name>)] { _id }"
const params = {}
client.fetch(query, params).then((data)=>{
  console.log(data)
})

Get all versions of a document

Query all versions (published, drafts, and release versions) of a document.

sanity::versionOf GROQ function

The sanity::versionOf GROQ function accepts a document ID and returns all versions of a document.

Use the function in a GROQ query and pass the document ID string.

import { createClient } from "@sanity/client";
import { getPublishedId } from "sanity"

const client = createClient({
    projectId: '<project-id>',
    dataset: '<dataset>',
    useCdn: false,
    apiVersion: '2025-02-19',
    token: '<token>',
    perspective: 'raw'
})

const query = "*[sanity::versionOf($publishedId)] { _id }"
const params = {
  publishedId: getPublishedId(documentId)
}
client.fetch(query, params).then((data)=>{
  console.log(data)
})

Gotcha

The function also works with the Query API and anywhere that supports GROQ functions.

Doc API

Use the document ID, along with the Doc API endpoint to retrieve all versions of a specific document. The includeAllVersions boolean query parameter returns all versions for the document.

Input

GET /vX/data/doc/production/movie_70981?includeAllVersions=true

Example response

{
  "documents": [
    {
      "_createdAt": "2018-06-13T08:57:45Z",
      "_id": "movie_70981",
      "_rev": "1kbjGQwz5Z0FmijO2l7Lwl",
      "_type": "movie",
      "_updatedAt": "2024-12-02T17:32:59Z",
      // ...
    },
    {
      "_createdAt": "2018-06-13T08:57:45Z",
      "_id": "drafts.movie_70981",
      "_rev": "3276f9d1-0343-4b78-a79e-8c6561942f1b",
      "_type": "movie",
      "_updatedAt": "2024-12-02T17:14:27Z",
      // ...
    },
    {
      "_createdAt": "2018-06-13T08:57:45Z",
      "_id": "versions.rHw6FBu82.movie_70981",
      "_rev": "a000fa99-072c-434c-8669-825103a111b7",
      "_type": "movie",
      "_updatedAt": "2024-11-27T18:36:19Z",
      // ...
    }
  ],
  "omitted": []
}

Use releases in perspective queries

Content Releases use a layering system that layers document versions atop one another, allowing you to create a custom perspective stack. You can learn more about layering in the Content Releases User Guide.

Perspective in addition to accepting the raw, published, and drafts states, also accepts a comma-separated list of release names. Releases take priority from left to right.

For example, in the perspective a,b,c you would see changes in a take priority over b and c, and changes in b take priority over c.

The published perspective is automatically added to the end, so even if a release only contains changes to one document, the response will include all matching published documents in addition to the release changes.

Query API

To query against a list of releases, use the perspective query parameter and order the release names by priority from left to right. For example: ?perspective=a,b,c.

Using a GROQ query such as *[_type == 'movie'] { _id } will return all document IDs that match the releases layer.

Input

GET https://<projectId>.api.sanity.io/vX/data/query/<dataset>?query‌‌‌‌‌‌=<GROQ-QUERY>&perspective=<release-name1>,<release-name2>

Example response

{
  "query": "*[_type == 'movie']{ _id }",
  "result": [
    { "_id": "a306e7cf-ea18-4a43-8ce2-0586073c41c8" },
    { "_id": "movie_10681" },
    { "_id": "movie_118340" },
    { "_id": "movie_126889" },
    { "_id": "movie_157336" },
    { "_id": "movie_17654" },

  ],
  "syncTags": ["s1:+jIWIw"],
  "ms": 5
}

JavaScript Client

In addition to the raw, published, and drafts values, the client also accepts an array of release name strings. You can add drafts to the end of the array to include drafts that aren't part of any release.

Edit the perspective value to insert your release names.

import { createClient } from "@sanity/client";

const client = createClient({
    projectId: '<project-id>',
    dataset: '<dataset>',
    useCdn: false, // Don't use the CDN for draft/release previewing
    apiVersion: '2025-02-19',
    token: '<token>',
    perspective: ['<release-name-1>', '<release-name-2>']
})

const query = "*[_type == 'movie']"
const params = {}
client.fetch(query, params).then((data)=>{
  console.log(data)
})

Another common pattern is to extend your client configuration for releases and draft preview by creating a new client from the existing one.

import { createClient } from "@sanity/client";

const client = createClient({
    projectId: '<project-id>',
    dataset: '<dataset>',
    useCdn: true,
    apiVersion: '2024-08-01',
    token: '<token>',
    perspective: 'published' //default
})

const previewClient = client.withConfig({
  useCdn: false,
  apiVersion: '2025-02-19',
  perspective: ['<release name>', 'drafts']
})

Trigger webhook by release state

The Release documents can be queried and trigger assigned webhooks.

The most useful way of triggering webhooks might be off the release state.

A release may have the following states:

  • active: The general state of a release that is not within one of the other states.
  • scheduled: A state resulting from calling the sanity.action.release.schedule action on the release.
  • published: A state resulting from either calling the sanity.action.release.publish action, or when a scheduled release is published due to reaching its publishAt time.
  • archived: A state resulting from calling the sanity.action.release.archive action.
  • deleted: A state resulting from calling the sanity.action.release.delete action on an archived release.

Additional transient states exist to indicate the asynchronous points when releases move between states:

  • scheduling/unscheduling: Intermediate states which will exist when moving to/from the scheduled state.
  • archiving/unarchiving: Intermediate states which will exist when moving to/from the archived state.
  • publishing: Intermediate state which will exist before reaching the published state. Note that a scheduled release will also transition through publishing.

To create a webhook that listens to all new releases, define a webhook rule as follows:

"rule":{
  "on":["create"],
  "filter":"_type == 'system.release'"
}

Additionally filters can enable triggering only on releases of a particular state. In this example only releases that have transitioned into a published state will trigger the webhook:

"rule": {
  "on": ["update"],
  "filter": "_type == 'system.release' && delta::changedAny(state) && state == 'published'"
}

Was this page helpful?