REST API Integrations and Webhooks

Read content out of Cosmic and push change notifications to other systems. Covers query filters, props, depth, sorting, the 404-on-empty behavior, and setting up a secured webhook.
Content in a CMS is only useful where people see it. That means other systems have to be able to read it, and ideally find out when it changes rather than polling for it.
Cosmic covers both: a REST API for reading and writing, and webhooks for pushing a notification when content changes. This lesson covers the query parameters worth knowing, how to set up a webhook, and what the receiving end actually gets.
Before You Start
-
A bucket with some content in it
-
Your Read key, from Settings > API keys
-
Webhooks require the Webhooks add-on. Everything in the REST API half of this lesson works on any plan
The REST API
Everything lives under one base URL:
Reads authenticate with a query parameter. Writes use an header, not a query parameter.
The simplest useful request:
The parameter takes JSON, URL-encoded. That is where filtering happens.
Filtering
Filter by type, and by any metafield value, using dot notation:
Status is a separate top-level parameter rather than part of the query:
This is the behavior that surprises people most often. A read key returns published objects only. Drafts are invisible until you pass . If you are building a preview mode, that parameter is what makes it work, and if your CMS shows content the site does not, this is almost always why.
The Parameters That Matter
limits which fields come back. Payloads get large fast, especially with rich text and nested objects, and most pages need four fields out of twenty:
On a list endpoint this is the single biggest thing you can do for response time.
controls how far related objects are expanded. It defaults to in v3, which means an object relationship comes back as an ID rather than the object itself. Set to get the related object, to get its relationships too. Only ask for the depth you render: each level multiplies the payload.
accepts , , , , , and any , each with a prefix for descending, plus . The default is , which is the manual ordering you set in the dashboard. For a blog you almost certainly want .
and handle pagination. Limit defaults to 1000 and is capped at 1000. For deep pagination there is also , which takes an object ID and pages by cursor. You cannot combine with .
Two Responses to Handle
Empty results return 404, not an empty array. This catches nearly everyone. A query matching nothing produces:
The SDK throws. So a category page with no posts yet will crash unless you catch it:
Write that helper once and use it everywhere. It is the difference between an empty state and a 500.
Very large responses return 413. The cap is 6MB. The fix is or pagination, and the error message says as much.
Building Queries Without Guessing
You do not have to construct these URLs by hand. Open API Tools from the objects list, the media page, or an object's actions menu. It builds the request from your current filters, including the read key, so you can copy a working URL straight into your code or a terminal.
Webhooks
A webhook makes Cosmic POST to a URL when content changes, so your systems find out immediately instead of polling.
Go to Settings > Webhooks. Webhooks are set per bucket, so a webhook on your production bucket does not fire for your staging one.
Click Add your first Webhook and fill in:
URL endpoint is where the POST goes. For testing, use a throwaway endpoint from webhook.site.
title is a label for you, something like .
resource is either or .
Object types narrows it to specific types. Leaving it empty means all of them.
events is where the important detail is.
The Three Events
Bucket webhooks fire on exactly three events:
Event | Fires when |
|---|---|
An object or media file is created | |
An existing one is changed | |
One is removed |
There is no event, and, more importantly, there is no publish event. Publishing a draft registers as , and creating something already published registers as .
So to react to a publish, subscribe to both and and check the status in your handler:
If you want a genuine trigger, that exists in workflow event triggers rather than bucket webhooks. Lesson 10 covers those. The two systems are separate and have different event lists, which is worth remembering when you are reading about one and configuring the other.
What Arrives at Your Endpoint
A JSON POST shaped like this:
Two headers come with it: and . You can route on those without parsing the body.
The Payload section controls how much of the object comes along. Switch it off and Cosmic skips filtering the object down, which makes delivery faster; the request still has a body, so a receiver that only needs to know something happened can route on the two headers and ignore it. Leave it on and set props to something like to keep the payload small. The limit is 6MB.
Securing the Endpoint
Cosmic does not sign webhook requests. There is no HMAC signature and no automatic secret header, so if you have used webhooks elsewhere, the verification step you are expecting is not there.
What you get instead is the Headers section, where you add your own key/value pairs sent with every request. Add a header with a secret value:
Then reject anything arriving without it:
Without this, your endpoint URL is the only thing standing between your systems and anyone who guesses it. Treat the header as required.
A Tip on Delivery
Webhook delivery is fire-and-forget. There are no retries, the request times out after 10 seconds, and there is no delivery log in the dashboard.
Three consequences worth designing around.
Respond immediately. Return a 200 first and do the work afterwards, in a queue or a background job. If your handler takes 11 seconds, the delivery is recorded as failed and nothing tries again.
Never make a webhook the only path. If a delivery fails, you will not be notified and you cannot look it up. Anything that must be consistent needs a reconciliation job that periodically queries the API and fixes drift.
Log on your side. Since Cosmic keeps no history, your receiver's logs are the only record of what arrived. Log every delivery before processing it.
Do This in Your Project
-
Open API Tools, build a query for one object type, and add to trim it to three fields
-
Run the same query with and confirm you see drafts
-
Go to webhook.site and copy the unique URL it gives you
-
In Settings > Webhooks, click Add your first Webhook, paste that URL, set resource to , and select and
-
Under Headers, add a secret key/value pair
-
Save, then edit an object in the dashboard and watch the request arrive
Read the payload that shows up. Knowing exactly what your endpoint receives is most of the work of building against it.
Up Next
Lesson 9: Chain Agents in a Workflow
Stage 4 moves to automation: workflows that chain multiple agents together and run without anyone starting them.
Up next
Chain Agents in a Workflow