Real-time Updates API > API reference

API reference

The Real-time Content API is built upon and extends the capabilities of the GraphQL Content Delivery API: theyboth support exactly the same authentication method, endpoints and GraphQL queries.

What's different is the domain you use to perform the POST request:

  • Content Delivery API:

  • Real-time Content API:

And of course the response you'll receive:

  • a call to the Content Delivery API simply returns a JSON with the response to the requested query, whereas

  • the same call to the Real-time Content API returns the URL of a persistent channel implementing the Server-Sent Events protocol.

Here's a diagram representing the differences between the two:

In the following video, you can see how how easy it is to interact with the API simply using curl:

Obtaining the URL of the channel

Using the same headers, API token and endpoint you use with the Content Delivery API, you can perform a request to and get back the URL of a Server-Sent Events channel that streams events as they occur:

# Content Delivery API call
~() curl \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'X-Include-Drafts: true' \
-d '{"query":"{ blogPost{ id } }"}'
{ "data": { "blogPost": { "id": "9721019" } } }
# Real-time Content API call
~() curl \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{"query":"{ blogPost{ id } }"}'
{ "url": "" }

The channel URL is ephemeral: after 15 seconds you will no longer be able to access it, so be sure to connect to it within a few seconds, or you will need to make a new call to get a new URL.

Receiving the events

Once you obtain the URL of a subscription channel, you can connect to it and stream events as they occur.

All modern browsers offer a native interface to connect to Server-Sent Events channels called EventSource:

const eventSource = new EventSource(
eventSource.addEventListener("open", () => {
console.log("connected to channel!");

Immediately after the connection, the channel will send an update event with the result of the GraphQL query. The same event will then be sent every time the result of the query changes due to a change of the underlying content:

eventSource.addEventListener("update", (event) => {
const result = JSON.parse(;
// result will be something like: { data: { blogPost: { id: "9721019" } } }
console.log("updated graphql result: ", result);

When something goes wrong, the channel can also send channelError events. The cause for the error could be an invalid GraphQL query for example:

eventSource.addEventListener("channelError", (event) => {
const error = JSON.parse(;
// error will be something like:
// {
// code: "INVALID_QUERY",
// message: "The query returned an erroneous response. Please consult the response details to understand the cause.",
// fatal: true,
// response: {
// errors: [
// {
// fields: ["query", "blogPost", "coverImage", "url", "wrongParameter"],
// locations: [{ column: 99, line: 1 }],
// message: "Field 'url' doesn't accept argument 'wrongParameter'",
// },
// ],
// },
// }
if (error.fatal) {

The fatal field in the error object is useful to know if the error is temporary (ie. connectivity/network problems) and therefore it is possible that additional update-type events are sent, or if the error is fatal (ie. invalid query) so you need to close the channel permanently.

Closed channels

An SSE channel stays open as long as possible, but it is perfectly normal that it closes after some time. The channel closure may be due to an automatic re-scaling of our servers to cope with an increase in requests, for example.

The official clients we have released handle this case transparently, and reconnect automatically if the channel closes. If you don't use one of our libraries, you'll have to make sure to reopen a new channel yourself in case the event happens.