👀 Our most exciting product launch yet 🚀 Join us May 8th for Sanity Connect

Scheduling API

Reference documentation for the Scheduling API. \n

Paid feature

The Scheduling API is available to users on Growth or higher plans.

Introduction

With the Scheduling API you can:

  • Publish or unpublish individual documents.
  • Create, edit, and delete schedules to run at any date in the future.
  • Immediately run any existing schedule, which will attempt to publish or unpublish all associated documents.

Info

A schedule is defined as a collection of multiple documents to be published or unpublished at any time in the future.

Protip

We also have an official studio plugin you can drop-in to existing projects that handles common scheduling requirements. The plugin does not yet handle scheduled unpublishing.

Authentication

All requests to the Scheduling API must be authenticated with a bearer token.

Ensure the following Authorization header is attached to all requests:

Authorization: Bearer <token>

Where <token> is your own personal API token or a generated Robot token.

All requests must be made over HTTPS. Requests made over HTTP or without authentication will fail.

Personal vs Robot tokens

If you’re creating a custom plugin to be used within the Sanity studio by multiple users, you’ll probably want to use the token of the current logged-in user.

Protip

Sanity Studio provides a client library importable as a part, which automatically handles authenticating requests on behalf of the current logged-in user.

// This example assumes execution within Sanity Studio V3
// (e.g. as a plugin or tool)
import {useClient} from 'sanity'

// Fetch all schedules on the `production` datatset` in project `hb6nr9ev`
// This will send a request authenticated against the current logged in user
const client = useClient({apiVersion: '2022-04-01'})
client
  .request({
    method: 'GET',
    uri: `/schedules/hb6nr9ev/production`
  })
  .then(data => {
		// Handle schedule data as you see fit
  })

If you’re creating a third-party application or script that handles scheduling operations on behalf of other users, then you’ll likely want to create a Robot token instead, which can be done in your project’s management console.

→ More information on Authentication in Sanity

Permissions

The following permissions are required for both document (publish and unpublish) and schedule (fetch, create, update, delete and execute) schedule operations:

  • Project Details read access
  • Document publish access

Rate / API limits

Gotcha

Schedule operations involving multiple documents are batched into a single transaction. This means that if a transaction involving multiple documents includes even a single document that you don’t have publish access to, the entire transaction will fail.

→ More information on Content Lake API rate limits

Status and error codes

401 Unauthorized
An invalid bearer token has been provided.

403 Forbidden
The current project isn’t on a plan that includes the Scheduling API.

or

The provided bearer token has insufficient permissions.

404 Not Found
The requested route could not be found.

5xx Errors
An internal error has occurred in Sanity. Please check our status page for more information.

Publishing rules

When publishing documents, the Scheduling API will either:

  • Publish the draft of any specified document IDs (if they exist)
  • Re-publish the document (if it’s already published and no drafts exist)

Operations that publish existing published documents will touch the document (updating _updatedAt) as well as trigger any linked webhooks.

Specifying document IDs

When specifying document IDs as part of a document or schedule operation, you need to specify the document ID without the draft. prefix.

For example, if you have a draft document in your Studio with ID drafts.69c5e394-1141-4cc8-a3a5-1f04addd6f34, remove draft. and specify only the ID: 69c5e394-1141-4cc8-a3a5-1f04addd6f34.

The Scheduling API will always publish drafts of any specified documents if they exist.

Specifying dates

Scheduled operations dates must comply with RFC 3339, and they must be in the following format: YYYY-MM-DDTHH:mm:ss.sssZ

The time zone is always UTC+00:00, as indicated by the Z suffix.

For example, 7:45 p.m. UTC on December 25, 2077 is represented as 2077-12-25T19:45:00.000Z

All dates must be in the future.

Schedules and your dataset

Schedules are a unique resource and are linked to, but do not exist within your Sanity project and dataset. It's important to understand the following behavior:

  • As schedules are not contained within a project’s dataset, you cannot query them via GROQ or GraphQL.
  • Deleting a dataset or project will immediately delete all schedules.
  • Deleting a document won’t delete any schedules associated with it.
  • sanity dataset export will not include schedules and sanity dataset import does not support importing schedules.
  • Server-side copying of datasets does not include schedules.
  • When a project is disabled or blocked, all scheduled publishes will invariably fail as mutations will not be allowed on the dataset.

Other caveats

  • The Scheduling API doesn’t validate documents prior to publishing. Any documents you publish (either immediately or at a later date as part of a schedule) will always attempt to publish, even if publication would be typically blocked due to custom validation rules in your Sanity Studio.

The Schedule Resource

{
  "id": "sch-28L09J9QA0M7ovPrClvXgfuGxXL",
  "name": "Example schedule",
  "description": "",
  "projectId": "hb6nr9ev",
  "dataset": "production",
  "author": "p-EiESybeCRamQ",
  "state": "scheduled",
  "stateReason": "created by user",
  "documents": [
    {
      "documentId": "01208c30-0872-465a-9e4d-9b02d8b9cf7d",
      "documentType": "article"
    }
  ],
  "createdAt": "2022-04-26T13:40:05.559107Z",
  "executeAt": "2077-12-15T19:45:05.053Z"
}

Attributes

  • idstring

    Unique identifier for the schedule

  • authorstring

    ID of the user who created this schedule

  • createdAtstring

    Date when the schedule was created (RFC 3339 date in the format YYYY-MM-DDTHH:mm:ss.sssZ)

  • datasetstring

    Sanity dataset name

  • descriptionstring

    A custom description for the schedule

  • documentsarray of objects

    An array of objects containing a key documentId that references a non-draft document ID.

  • executeAtstring

    Date when the schedule will be run (RFC 3339 date in the format YYYY-MM-DDTHH:mm:ss.sssZ)

  • namestring

    A custom name for the schedule

  • projectIdstring

    Sanity project ID

  • statestring

    The current state of the schedule. Can be either scheduled, succeeded, executing or cancelled. Schedules that fail to run will be marked as cancelled.

  • stateReasonstring

    A description for the current schedule state. If a schedule fails to run, the reason for failure will be displayed here.

HTTP API

Document HTTP endpoints

Publish

POST /publish/:projectId/:dataset

Publish any number of documents immediately.

Request body (required)

A JSON array of objects. Each object must contain a key documentId that references a non-draft document ID.

Example

Immediately publish document with ID aaa3d1dd-30c3-4c79-ab18-e9c2cb586339

Example Request

curl -X "POST" "https://api.sanity.io/v1/publish/hb6nr9ev/production" \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d $'[
       {
         "documentId": "aaa3d1dd-30c3-4c79-ab18-e9c2cb586339"
       }
     ]'

Response

// 200 OK (JSON)
{
  "transactionId": "AXfzpiiJdFhpbwBLvIGnUb"
}

Unpublish

POST /unpublish/:projectId/:dataset

Unpublish any number of documents immediately.

Request body (required)

A JSON array of objects. Each object must contain a key documentId containing a non-draft document ID.

Example

Immediately unpublish documents with ID 38eb7eb8-2c13-4229-9465-4434da1a8e90 and 8b859a22-321d-4903-a443-6ffa995d3500

Request

curl -X "POST" "https://api.sanity.io/v1/unpublish/hb6nr9ev/production" \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d $'[
      {
        "documentId": "38eb7eb8-2c13-4229-9465-4434da1a8e90"
      },
      {
        "documentId": "8b859a22-321d-4903-a443-6ffa995d3500"
      }
    ]'

Response

// 200 OK (JSON)
{
  "transactionId": "A5Y41hFe5J3wNnB7OGV71r"
}

Schedule HTTP endpoints

Get schedules

GET /schedules/:projectId/:dataset

Fetch all schedules, ordered by createdAt in reverse chronological order

Params

  • authorstring

    A single user ID to filter returned schedules by.

  • documentIdsstring

    A comma-separated list of document IDs to filter returned schedules by.

  • offsetnumber

    Number to off offset returned schedules by.

  • limitnumber

    Number to limit returned schedules by. A value of 0 will return all schedules.

  • statestring

    Schedule state to filter by. Valid values are succeeded, scheduled, executing or cancelled.

Example

Fetch all succeeded schedules created by user poLhU1V3X and limit to a single item.

Request

curl "https://api.sanity.io/v1/schedules/hb6nr9ev/production?state=succeeded&author=poLhU1V3X&limit=1" \
     -H 'Authorization: Bearer <token>'

Response

// 200 OK (JSON)
{
  "schedules": [
    {
      "id": "sch-28MRSuc1Ij4xtNa1rNbhTlMAszj",
      "name": "My example schedule",
      "description": "",
      "projectId": "hb6nr9ev",
      "dataset": "production",
      "author": "poLhU1V3X",
      "state": "succeeded",
      "stateReason": "execution completed",
      "documents": [
        {
          "documentId": "f28fe6ce-0454-42c2-8a9a-c469fbf79281",
          "documentType": "article"
        }
      ],
      "createdAt": "2022-04-27T01:54:31.536236Z",
      "executeAt": "2022-04-27T01:55:00Z"
    }
  ]
}

Get schedule by ID

GET /schedules/:projectId/:dataset/:scheduleId

Fetch schedules by ID.

Multiple schedule IDs can be specified as a comma-separated list.

Params

  • authorstring

    A single user ID to filter returned schedules by.

  • documentIdsstring

    A comma-separated list of document IDs to filter returned schedules by.

  • statestring

    Schedule state to filter by. Valid values are succeeded, scheduled or cancelled.

Example

Fetch the schedule with ID sch-28MRSuc1Ij4xtNa1rNbhTlMAszj

Request

curl "https://api.sanity.io/v1/schedules/hb6nr9ev/production/sch-28MRSuc1Ij4xtNa1rNbhTlMAszj" \
     -H 'Authorization: Bearer <token>'

Response

// 200 OK (JSON)
{
  "schedules": [
    {
      "id": "sch-28MRSuc1Ij4xtNa1rNbhTlMAszj",
      "name": "March update",
      "description": "",
      "projectId": "hb6nr9ev",
      "dataset": "production",
      "author": "poLhU1V3X",
      "state": "succeeded",
      "stateReason": "execution completed",
      "documents": [
        {
          "documentId": "f28fe6ce-0454-42c2-8a9a-c469fbf79281",
          "documentType": "article"
        }
      ],
      "createdAt": "2022-04-27T01:54:31.536236Z",
      "executeAt": "2022-04-27T01:55:00Z"
    }
  ]
}

Create schedule

POST /schedules/:projectId/:dataset

Create a new schedule to publish or unpublish a set of documents.

Request body (required)

A JSON array of objects with the key documents. Each object must contain a key documentId that references a non-draft document ID. The object can optionally include a key ifRevisionId, which must match the document's _rev value in order to proceed with the publish or unpublish action.

Params

  • REQUIREDnamestring

    A custom name for the schedule.
    Make it human-readable and understandable.

  • executeAtstring

    Execution date and time of the schedule.
    The time is in UTC format with a Z suffix, corresponding to the UTC+00:00 time zone.
    Format: YYYY-MM-DDTHH:mm:ss.sssZ
    Example: 2077-12-25T07:45:00.000Z

  • descriptionstring

    A custom description for the schedule.
    It helps understand the purpose of the schedule.

  • action"publish" | "unpublish"

    Optional string.
    Accepts the following values:

    • publish
    • unpublish

    If action has no value, it defaults to publish.

  • ifRevisionIdstring

    Run the schedule only if the document _rev value matches ifRevisionId.

Example

Create a schedule to publish two documents on 25 December 2025.

Request

curl -X "POST" "https://api.sanity.io/v1/schedules/hb6nr9ev/production" \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d $'{
      "documents": [
        {
          "documentId": "01208c30-0872-465a-9e4d-9b02d8b9cf7d"
        },
        {
          "documentId": "9f515369-87f4-4c70-9009-1c9d7a14aec8"
        }
      ],
      "name": "December 2025 release",
      "description": "Documents to publish at the end of 2025",
      "executeAt": "2025-12-25T19:45:00.000Z"
    }'

Response

// 200 OK (JSON)
{
  "id": "sch-28MkGjFSYRBSlcKExN2WBnBxtdQ",
  "name": "December 2025 release",
  "description": "Documents to publish at the end of 2025",
  "projectId": "hb6nr9ev",
  "dataset": "production",
  "author": "p-EiESybeCRamQ",
  "state": "scheduled",
  "stateReason": "created by user",
  "documents": [
    {
      "documentId": "01208c30-0872-465a-9e4d-9b02d8b9cf7d",
      "ifRevisionId": ""
    },
    {
      "documentId": "9f515369-87f4-4c70-9009-1c9d7a14aec8",
      "ifRevisionId": ""
    }
  ],
  "createdAt": "2022-04-27T04:29:08.668197Z",
  "executeAt": "2025-12-25T19:45:00Z"
}

Update schedule

PATCH /schedules/:projectId/:dataset/:scheduleId

Update an existing schedule.

Params

  • descriptionstring

    A custom description for the schedule.
    It helps understand the purpose of the schedule.

  • documentsarray of objects

    An array of objects containing a key documentId that references a non-draft document ID.

  • executeAtstring

    Execution date and time of the schedule.
    The time is in UTC format with a Z suffix, corresponding to the UTC+00:00 time zone.
    Format: YYYY-MM-DDTHH:mm:ss.sssZ
    Example: 2077-12-25T07:45:00.000Z

  • namestring

    A custom name for the schedule.
    Make it human-readable and understandable.

  • statestring

    The target state of the schedule. Can only be set to cancelled.

Gotcha

Only schedules with a scheduled state can be marked as cancelled.

It’s not possible to cancel already completed schedules.

A schedule cannot have its state changed once in a cancelled state.

Example

Update schedule with ID sch-28MjyBMDGxT5Gxshj4rYtWClbUq to run on 12:00PM Jan 1, 2077 and publish document with ID 27aef7e9-7c9f-4b67-9c46-d786b54d0624

Request

curl -X "PATCH" "https://api.sanity.io/v1/schedules/hb6nr9ev/production/sch-28MjyBMDGxT5Gxshj4rYtWClbUq" \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d $'{
      "executeAt": "2077-01-01T12:00:00.000Z",
      "documents": [
        {
          "documentId": "27aef7e9-7c9f-4b67-9c46-d786b54d0624"
        }
      ]
    }'

Response

// 200 OK with empty body

Run schedule

POST /schedules/:projectId/:dataset/:scheduleId/publish

Run an existing schedule immediately (publish all its documents).

Multiple schedule IDs can be specified as a comma-separated list.

Example

Run schedule with ID sch-26jr9toRuHMfFqdCtHONjHB2nl7 immediately

Request

curl -X "POST" "https://api.sanity.io/v1/schedules/hb6nr9ev/production/sch-26jr9toRuHMfFqdCtHONjHB2nl7/publish" \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json'

Response

// 200 OK
{
  "schedules": [
    {
      "id": "sch-26jr9toRuHMfFqdCtHONjHB2nl7",
      "name": "May release",
      "description": "",
      "projectId": "hb6nr9ev",
      "dataset": "production",
      "author": "poLhU1V3X",
      "state": "succeeded",
      "stateReason": "execution completed",
      "documents": [
        {
          "documentId": "b80b96b7-24dc-4c49-a5c3-340ef1750b8f",
          "documentType": "article"
        }
      ],
      "createdAt": "2022-03-22T11:14:47.281244Z",
      "executeAt": "2022-05-20T11:30:00Z",
      "executedAt": "2022-04-27T06:19:53.267576Z",
      "transactionId": "AXfzpiiJdFhpbwBLvIYojP"
    }
  ]
}

Was this article helpful?