Scheduling API

Reference documentation for the Scheduling API.

Paid feature

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

Introduction

With the Scheduling API you can:

  • Publish or un-publish 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 all associated documents

Info

A schedule is defined as a collection of multiple documents to be published 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.

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 V2 
// (e.g. as a plugin or tool)
import sanityClient from 'part:@sanity/base/client'

// Fetch all schedules on the `production` datatset` in project `hb6nr9ev`
// This will send a request authenticated against the current logged in user
sanityClient
  .withConfig({apiVersion: '2022-04-01'})
  .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 probably 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 un-publish) 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.

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 only need to specify the non-draft document ID.

For example, if you have a draft document in your Studio with the ID drafts.69c5e394-1141-4cc8-a3a5-1f04addd6f34, you only need specify the ID 69c5e394-1141-4cc8-a3a5-1f04addd6f34 (without the drafts path prefix).

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

Specifying dates

When specifying dates in schedule operations, they must be presented in RFC-3339 format (YYYY-MM-DDTHH:mm:ss.sssZ).

For example, 7:45PM on 25 December 2077 would be represented as 2025-12-25T19:45:00.000Z

Dates provided are zero UTC offset, as denoted by the Z suffix.

All dates must be set 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 either 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.
  • You cannot create schedules that un-publish documents.

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"
}

Un-publish

POST /unpublish/:projectId/:dataset

Un-publish 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 un-publish 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.

Request body (required)

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

Params

  • REQUIREDnamestring

    A custom name for the schedule

  • executeAtstring

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

  • descriptionstring

    A custom description for the schedule

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

  • 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

  • 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?