Webhooks API
API endpoints for managing Sanity webhooks
Sanity provides two types of webhooks, transaction and document. Currently document webhooks are preferred because they are more flexible and powerful.
A document webhook triggers every time a document is created, updated, or deleted. If a transaction updates 3 documents, 3 webhooks will be executed. Document webhook also allows for more granular filtering and customisable payloads with GROQ.
For more information about document webhooks click here.
A transaction webhook triggers once per dataset , meaning if you batch together multiple document mutations in one transaction only one webhook will be executed.
GET /v2021-10-04/hooks/projects/${projectId}
Request
curl 'https://api.sanity.io/v2021-10-04/hooks/projects/${projectId}' \ --header 'Authorization: Bearer ${token}'
Response
[
{
"type": "document",
"rule": {
"on": [
"create",
"update"
],
"filter": "_type == \"article\"",
"projection": "{ _id, name }"
},
"apiVersion": "v2021-03-25",
"httpMethod": "POST",
"includeDrafts": false,
"headers": {},
"secret": "thisIsAsecret",
"id": "nCA0wzdJXR1cVadR",
"name": "test",
"projectId": "exx11uqh",
"dataset": "*",
"url": "https://www.example.com/",
"createdAt": "2022-07-22T10:48:21.392Z",
"createdByUserId": "psh9hAsjB",
"isDisabled": false,
"isDisabledByUser": false,
"deletedAt": null,
"description": null
},
{
"type": "transaction",
"id": "yyB57FRgCOCeLAtL",
"name": "Transactio webhook",
"projectId": "exx11uqh",
"dataset": "webhook-test",
"url": "https://www.example.com/",
"createdAt": "2022-07-22T10:48:21.392Z",
"createdByUserId": "pdakbqZhE",
"isDisabled": false,
"isDisabledByUser": false,
"deletedAt": null,
"description": null
},
...
]
GET /v2021-10-04/hooks/projects/${projectId}/${hookId}
Request
curl 'https://api.sanity.io/v2021-10-04/hooks/projects/${projectId}/${hookId}' \ --header 'Authorization: Bearer ${token}'
Response
{
"type": "document",
"rule": {
"on": [
"create",
"update"
],
"filter": "_type == \"article\"",
"projection": "{ _id, name }"
},
"apiVersion": "v2021-03-25",
"httpMethod": "POST",
"includeDrafts": false,
"headers": {},
"secret": "thisIsAsecret",
"id": "nCA0wzdJXR1cVadR",
"name": "test",
"projectId": "exx11uqh",
"dataset": "*",
"url": "https://www.example.com/",
"createdAt": "2022-07-22T10:48:21.392Z",
"createdByUserId": "psh9hAsjB",
"isDisabled": false,
"isDisabledByUser": false,
"deletedAt": null,
"description": null
}
POST /v2021-10-04/hooks/projects/{projectId}
Request
curl \ 'https://api.sanity.io/v2021-10-04/hooks/projects/${projectId}' \ --request POST \ --header 'Authorization: Bearer ${token}' \ --json @- << EOF { "type":"document", "name":"name", "url":"https://www.example.com/", "httpMethod":"POST", "apiVersion":"v2021-03-25", "includeDrafts":false, "dataset":"*", "rule":{ "on":["create"], "filter":"_type == 'article'", "projection":"{_id}" }, "description":"description", "headers":{}, "secret":"MySecret", "isDisabledByUser":false } EOF
Response
{
"type": "document",
"rule": {
"on": [
"create"
],
"filter": "_type == 'article'",
"projection": "{_id}"
},
"filter": null,
"projection": null,
"apiVersion": "v2021-03-25",
"httpMethod": "POST",
"includeDrafts": false,
"headers": {},
"secret": "MySecret",
"id": "RHlOxIEkZd8rncl6",
"name": "name",
"projectId": "exx11uqh",
"dataset": "*",
"url": "https://www.example.com/",
"createdAt": "2023-07-21T09:13:30.754Z",
"createdByUserId": "psv96AOjB",
"isDisabled": false,
"isDisabledByUser": false,
"deletedAt": null,
"description": "description"
}
REQUIREDtypestring
'document'
REQUIREDnamestring
Name of webhook
REQUIREDurlstring
The URL field is where you specify the endpoint to which the webhook request is sent.
REQUIREDdatasetstring
Which dataset should this trigger for.
'*' means all datasets in the project.
descriptionstring
Optional description to add helpful context to the webhook.
rule.onstring[]
Webhooks can be triggered when a document is created, updated, deleted, or any combination of these.
- 'create': triggers on the creation of a new document.
- 'update': triggers on every change to a document once created.
- 'delete': triggers on the deletion of a document
rule.filterstring
A GROQ filter specifying which documents will, when changed, trigger your webhook. A filter is what you commonly see between the
*[
 and]
 in a GROQ query. This field supports all the GROQ functions you'd expect and has additional support for functions in thedelta::
 namespace, as well asbefore() and after()
.If left empty, it will apply to all documents (
*[]
)rule.projectionstring
A GROQ projection defining the payload (or body) of the outgoing webhook request. This field supports GROQ functions in the
delta::
 namespace, as well asbefore() and after()
.If left empty, it will include the whole document after the change that triggered it.
See more information about GROQ-projections here
apiVersionstring
Which API version to use for the GROQ filter and projection. Defaults to the latest API version for the GROQ query API
httpMethodstring
This field configures the webhook's HTTP request method. It can be set to POST, PUT, PATCH, DELETE, or GET. Some endpoints require incoming requests to use a specific method to work.
includeDraftsboolean
Whether or not to trigger on draft changes
headersRecord<string, string>
Additional HTTP headers. You can add multiple headers. A common example is adding an
Authorization: Bearer <token>
header to authenticate the webhook request.secretstring
To let receiving services verify the origin of any outgoing webhook, you may add a secret that will be hashed and included as part of the webhook request's headers. You may find our webhook toolkit library helpful for working with secrets.
isDisabledByUserboolean
Set to 'true' to disable the webhook and prevent it from triggering.
POST /v2021-10-04/hooks/projects/{projectId}
Request
curl \ 'https://api.sanity.io/v2021-10-04/hooks/projects/${projectId}' \ --request POST \ --header 'Authorization: Bearer ${token}' \ --json @- << EOF { "type":"transaction", "name":"name-transaction", "url":"https://www.example.com/", "dataset":"*", "description":"description", "isDisabledByUser":false } EOF
Response
{
"type": "transaction",
"id": "8ngGSobiUAzpw4cl",
"name": "name-transaction",
"projectId": "exx11uqh",
"dataset": "*",
"url": "https://www.example.com/",
"createdAt": "2023-07-21T10:32:48.424Z",
"createdByUserId": "psv96AOjB",
"isDisabled": false,
"isDisabledByUser": false,
"deletedAt": null,
"description": "description"
}
REQUIREDtypestring
'transaction'
REQUIREDdatasetstring
Which dataset should this trigger for.
'*' means all datasets in the project.
REQUIREDurlstring
The URL field is where you specify the endpoint to which the webhook request is sent.
REQUIREDnamestring
Name of webhook
descriptionstring
Optional description to add helpful context to the webhook
isDisabledByUserboolean
Set to 'true' to disable the webhook and prevent it from triggering.
PATCH /v2021-10-04/hooks/projects/{projectId}/{id}
Request
curl \ 'https://api.sanity.io/v2021-10-04/hooks/projects/${projectId}/${id}' \ --request PATCH \ --header 'Authorization: Bearer ${token}' \ --json @- << EOF { "isDisabledByUser":true } EOF
Response
{
"type": "transaction",
"id": "8ngGSobiUAzpw4cl",
"name": "name-transaction",
"projectId": "exx11uqh",
"dataset": "*",
"url": "https://www.example.com/",
"createdAt": "2023-07-21T10:32:48.424Z",
"createdByUserId": "psv96AOjB",
"isDisabled": false,
"isDisabledByUser": true,
"deletedAt": null,
"description": "description"
}
DELETE /v2021-10-04/hooks/projects/{projectId}/{id}
Request
curl \ 'https://api.sanity.io/v2021-10-04/hooks/projects/${projectId}/${id}' \ --request DELETE \ --header 'Authorization: Bearer ${token}'
Response
{
"id": "8ngGSobiUAzpw4cl",
"deleted": 1
}
GET /v2021-10-04/hooks/projects/${projectId}/{id}/attempts
Request
curl \ 'https://api.sanity.io/v2021-10-04/hooks/projects/${projectId}/${id}/attempts' \ --header 'Authorization: Bearer ${token}'
Response
[
{
"id": "ROnIqO5K2v8fvJGz-YLiSJVES65n2uvB1osaQEMEXUqmoUmPn",
"projectId": "exx11uqh",
"inProgress": false,
"resultBody": "OK",
"resultCode": 200,
"duration": 39,
"isFailure": false,
"failureReason": null,
"createdAt": "2023-07-21T10:46:40.147Z",
"updatedAt": "2023-07-21T10:46:40.239Z",
"deletedAt": null,
"messageId": "ROnIqO5K2v8fvJGz-aa1cmvIZmBc1lFSopuuGrJbNNyfq6VVM",
"hookId": "ROnIqO5K2v8fvJGz"
},
{
"id": "ROnIqO5K2v8fvJGz-54BtIsybhwP9Q4FDFNVnjeYbKe6r6mV3",
"projectId": "exx11uqh",
"inProgress": false,
"resultBody": "Unauthorized",
"resultCode": 401,
"duration": 42,
"isFailure": true,
"failureReason": "http",
"createdAt": "2023-07-21T10:45:40.226Z",
"updatedAt": "2023-07-21T10:45:40.356Z",
"deletedAt": null,
"messageId": "ROnIqO5K2v8fvJGz-Ig96In7jBaYXRcx4qIDS6SYXP2fYeaoV",
"hookId": "ROnIqO5K2v8fvJGz"
},
...
]