Listen API reference
Reference documentation for the Listen HTTP endpoint.
Use the listen endpoint to receive events whenever documents are modified. This endpoint follows the server-sent events protocol using the MIME type text/event-stream. The backend holds the connection open and streams events as they occur for any documents matching the GROQ query.
In most cases, you should use the Live Content API instead for new projects.
Authentication
Listening for drafts, versions, or documents in private datasets requires an authenticated request.
Base API server URL
Sanity API base URL
https://{projectId}.api.sanity.io/{apiVersion}Variables
- projectIdstringdefault:
"projectId"Project ID
- apiVersionstringdefault:
"v2025-02-19"API version
Endpoints
Stream document mutation events
/data/listen/{dataset}Streams events whenever documents matching the GROQ query are modified. This is a live API adhering to the server-sent events standard.
The server sends a : comment every 15 seconds to keep the connection alive. It closes the connection after about four hours, and when it restarts, without sending a disconnect event. Reconnect when the connection closes, and use enableResume to avoid missing events in between.
Authentication errors return an HTTP error before the stream starts: 400 for a malformed Authorization header and 401 for an invalid token. Any other error arrives as events on the stream, not as an HTTP status code. The response status is 200, followed by a channelError event and a disconnect event. In most cases, data.error is an object with a description and a type, and the disconnect event has the reason error. A dataset that doesn't exist is the exception: data.error is the string Dataset not found, with the details in data.message, and the disconnect event has no data. Error descriptions you might see include:
unexpected end-of-file, expected expression(typequeryParseError, the exact text varies): thequeryparameter isn't valid GROQ.no query(typequeryParseError): thequeryparameter is missing.Unknown query parameter "NAME"(typehttpUnknownQueryStringParameters): the request includes a parameter the endpoint doesn't accept.invalid listener visibility "VALUE"(typevalidationError):visibilityisn'ttransactionorquery.Invalid effectFormat specified: VALUE(typevalidationError):effectFormatisn'tmendoza.Invalid includeAllVersions specified: VALUE(typevalidationError):includeAllVersionsisn't a boolean.Invalid listener resume token: REASON(typevalidationError):enableResumeis true and the last event ID isn't a valid event ID.Max listener limit exceeded at N: the dataset already has the maximum number of concurrent listeners.
Path parameters
The dataset to stream events from
Query parameters
The GROQ query used to filter the events. Only the top-level filter portion of the query is used. Anything else, including projection, subqueries, slicing, or aggregation, is ignored.
- $-paramsstring
Any $-prefixed parameters to include in the GROQ query.
Include the resulting document in addition to the changes. The HTTP API defaults to false. The
listen()method in@sanity/clientsends true unless you setincludeResultto false.Include the document as it looked before the change.
Include the mutations applied as part of the transaction.
Specifies whether events should be sent as soon as a transaction has been committed (transaction, default), or only after they are available for queries (query). Note that this is best-effort, and listeners with query may in certain cases (notably with deferred transactions) receive events that are not yet visible to queries. The visibility event field indicates the actual visibility.
Send a prolog of 2056 no-op characters for compatibility with older browsers. Any value, including false, enables it.
- effectFormatstring
If set to the only allowed value mendoza, an additional field effects is included in the returned payload with mutation effects in the Mendoza specification.
Set to true to also receive events for version documents (IDs that start with
versions.). Draft documents are included without this parameter, if the request's token can read them. Requires API version 2025-02-19 or later; earlier API versions ignore this parameter.Set to true to let a reconnecting listener resume where it left off. Send the ID of the last event you received in the
Last-Event-IDheader or thelastEventIdparameter. If the listener can resume, the stream starts with awelcomebackevent followed by the events you missed. If it can't, you receive aresetorwelcomeevent instead, and should refetch your local state. An invalid ID returns the errorInvalid listener resume token.- lastEventIdstring
The ID of the last event you received. Used to resume when
enableResumeis true. Ignored when theLast-Event-IDheader is set. - tagstring
A request tag that identifies the listener request in logs.
Header parameters
- Last-Event-IDstring
The ID of the last event you received. Used to resume when
enableResumeis true. Takes precedence over thelastEventIdparameter.
Responses
Successfully started streaming operation. Errors after this point arrive as channelError events.
- idstring
A unique ID for this event. Treat it as an opaque string. For
mutationevents, it starts with the transaction ID and the document ID (transactionId#documentId) and may be followed by@and an encoded stream position. WhenenableResumeis true, send the last ID you received as theLast-Event-IDheader to resume from that event. - eventstring
The type of SSE message
The message payload. For
disconnectevents,reasoniserrorafter achannelError, orforced by providerwhen the listener was removed on the server.Show child attributes
- eventIdstring
The same value as the event's
id. - documentIdstring
- transactionIdstring
- transitionstring
Whether the document was updated and still matches the query, started matching it, or stopped matching it.
- identitystring
The ID of the user or token that made the change.
- mutationsarray
The mutations applied to the document. Omitted when
includeMutationsis false.Show child attributes
items
- object
- resultobject
The document after the change. Only included when
includeResultis true. - previousobject
The document before the change. Only included when
includePreviousRevisionis true. - previousRevstring
- resultRevstring
- timestampstring (date-time)
- visibilitystring
The visibility the event was actually delivered with.
- effectsobject
Mendoza patches (
applyandrevert) describing the change. Only included wheneffectFormatismendoza. - transactionCurrentEventinteger
The position of this event among the events generated by the same transaction, starting at 1.
- transactionTotalEventsinteger
The total number of events generated by the transaction. Use it with
transactionCurrentEventto tell when you've received every event from a transaction. - messageDispatchedAtstring (date-time)
When the backend dispatched the event.
- object
The payload for other event types.
text/event-stream{
"event": "welcome",
"id": "w#w@PV9raxj9b7a5XxZvMSwFWjYCHSQ",
"data": {
"listenerName": "Ua6BR3GwQ14cnZXrgwCdsF"
}
}{
"event": "welcomeback",
"id": "w#w@PV9TaBj9b7a5XxZvMSwFWnRa3Og",
"data": {
"listenerName": "a4h9CCMcZeRP5QcyiFjQyh"
}
}{
"event": "reset",
"data": {
"listenerName": "a4h9CCMcZeRP5QcyiFjQyh"
}
}{
"event": "mutation",
"id": "pzeuul-awl-b69-ij3-g8862vgf3#drafts.38123cba-286c-45a0-a6d1-3cc4dc43748a",
"data": {
"eventId": "pzeuul-awl-b69-ij3-g8862vgf3#drafts.38123cba-286c-45a0-a6d1-3cc4dc43748a",
"documentId": "drafts.38123cba-286c-45a0-a6d1-3cc4dc43748a",
"transactionId": "pzeuul-awl-b69-ij3-g8862vgf3",
"transition": "update",
"identity": "pJNdYiKyA",
"mutations": [],
"previousRev": "08p48x-bog-ro2-8sh-brvd69hcd",
"resultRev": "pzeuul-awl-b69-ij3-g8862vgf3",
"timestamp": "2017-11-22T10:24:01.801339Z",
"visibility": "transaction",
"transactionCurrentEvent": 1,
"transactionTotalEvents": 1,
"messageDispatchedAt": "2017-11-22T10:24:01.812744Z"
}
}{
"event": "channelError",
"data": {
"error": {
"description": "unexpected end-of-file, expected expression",
"end": 7,
"query": "*[_id==",
"start": 7,
"type": "queryParseError"
}
}
}{
"event": "channelError",
"data": {
"error": "Dataset not found",
"statusCode": 404,
"message": "Dataset \"production\" not found for project ID \"projectId\""
}
}{
"event": "disconnect",
"data": {
"reason": "error"
}
}The Authorization header is malformed.
- errorstring
- messagestring
- statusCodeinteger
- errorCodestring
application/json{
"error": "Bad Request",
"message": "Invalid authorization header - please double-check token",
"statusCode": 400
}The token is invalid.
- errorstring
- messagestring
- statusCodeinteger
- errorCodestring
application/json{
"message": "Session not found",
"error": "Unauthorized",
"statusCode": 401,
"errorCode": "SIO-401-ANF"
}