What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
APIs
HTTP status codes from the Agility Content Fetch and GraphQL APIs (400, 401, 404, 408, 429), empty lists, rate limits, and how CDN caching works for live and preview requests.
This page lists the HTTP status codes the Content Fetch API and the GraphQL API return, what each one means for your code, and how responses are cached. Use it when you build error handling, retries or caching around Agility content.
For how to authenticate and make your first request, see Content Fetch API.
| Code | When you get it | What to do |
|---|---|---|
200 OK | The request worked. For a content list this includes a list with no items in it. | Use the response. |
400 Bad Request | The filter parameter has an error (REST or GraphQL), or the API type in the URL is not fetch or preview. | Fix the request. Retrying it unchanged will fail again. |
401 Unauthorized | The APIKey header is missing, or the key is not valid for this instance. | Check the key, its type (fetch or preview) and its expiry under Settings > API Keys. |
404 Not Found | The item, page or other resource you asked for was not found. On live endpoints this includes content that has not been published. | Treat as "not there". Don't retry in a loop. |
408 Request Timeout | The request took longer than 30 seconds to process. | Wait at least 30 seconds, then retry. The 408 response is cached for 30 seconds (see below). |
429 Too Many Requests | You sent more than 10 uncached requests in one second. | Slow down and retry with back-off. Cache responses on your side. |
Since August 2023, a request whose filter parameter contains an error returns 400 Bad Request instead of 500. This applies to both the REST API and GraphQL. A 400 means the request itself is wrong, so log the response body and fix the filter rather than retrying.
For the filter syntax and operators, see GraphQL & Rest API Filtering.
The API also returns 400 when the API type segment of the URL is something other than fetch or preview. For example, this request (sent on 2026-10-03):
curl -i "https://api.aglty.io/{guid}/blah/en-us/list/posts" -H "APIKey: {your-key}"
returned:
HTTP/2 400
cache-control: private, no-store
Invalid API type (must be fetch or preview)
Every Fetch API and GraphQL request needs an APIKey header. Observed on 2026-10-03:
APIKey header: 401 with the body Missing API Key.401 with the body Invalid API Key for {guid}.Both responses carried cache-control: private, no-store, so a fixed key takes effect on the next request. The GraphQL endpoint (POST https://api.aglty.io/v1/{guid}/{fetch|preview}/{locale}/graphql) returned the same 401 messages.
Remember that keys have a type. A fetch key reads published content from the fetch endpoints. A preview key reads the latest saved (staging) content from the preview endpoints. The key must support the API type in the URL. Keys can also have an expiry date, so check the expiry when a key that used to work starts returning 401.
Asking for a single item, page or gallery that isn't there returns 404. On the live (fetch) endpoints, "isn't there" includes content that exists but has never been published, so a 404 for an item you can see in the CMS usually means it hasn't been published yet. The same request with a preview key and the preview endpoint will return the staging version.
Content lists behave differently. Since July 2024, an empty content list always returns an empty result, not a 404. Before that change, a list where no item had ever been published could return 404, while a list whose items had all been unpublished or deleted returned an empty result. Now both cases look the same:
{
"items": [],
"totalCount": 0
}
So for lists, check items.length (or totalCount) rather than catching a 404. Older code that treats a 404 from a list endpoint as "empty" is harmless, but for lists with no published items it no longer runs.
List endpoints return 10 items by default. Pass take (maximum 250) and page with skip when a list can be longer. A short page is not an error: it means you reached the end.
When a request takes longer than 30 seconds to process, the API responds with 408 Request Timeout. Since August 2023 the cache-control header on a 408 response sets a 30 second cache lifetime (it used to be 24 hours).
In practice this means:
ContentLinkDepth, avoid ExpandAllContentLinks=true on large lists, use fields to return only the fields you need, and page with take and skip.The Fetch API allows 10 uncached requests per second. Above that it responds with 429 Too Many Requests.
Responses served from the CDN cache do not count towards this limit. The limit is about requests that reach the API itself, for example the first request for a URL, or requests for many different URLs in a burst.
Ways to stay under it:
take up to 250 instead of many small pages, and request linked content with ContentLinkDepth rather than one call per linked item.The Fetch API and GraphQL API are served through a CDN. Each request is either:
When content is published, Agility invalidates the affected cached responses, so the next request gets the new version. See Content Delivery & CDN Architecture for the full picture, including the separate CDN in front of your own site.
Error responses we observed (400 and 401) carried cache-control: private, no-store, so they are not reused. The 408 response is the exception described above: it is cached for 30 seconds.
Agility's CDN caches API responses. Your website or app usually has its own cache as well (for example, the Next.js data cache, or the CDN of your host). Publishing in Agility does not clear that layer for you. Use webhooks to tell your app what changed, then revalidate the matching pages or cache entries.
Live (fetch) | Preview (preview) | |
|---|---|---|
| Key type | Fetch key | Preview key |
| Returns | Published content | The latest saved content, including staging changes |
| Typical use | Production site | Preview and editing environments |
Use the preview key only on the server or in a preview environment. It reads unpublished content.