Agora CMS API
Ágora CMS is a headless content management system that exposes all your editorial content through a standard REST API. You can integrate it into any frontend — Next.js, Astro, Nuxt, a mobile app or a Python script — without proprietary SDKs or special configuration. Each workspace has its own API Key and its own endpoints. All you need is HTTP and JSON.
Base URL
All requests are made to:
https://app.agorastack.com/api/v1
The current API version is v1. When breaking changes are introduced, a v2 will be published while keeping the previous version active for at least 12 months.
Authentication
All requests require the X-API-Key header with your workspace API Key.
X-API-Key: your-api-key You can obtain and manage your API Key in Settings → API inside the admin panel.
?api_key= query string parameter is disabled
in production for security reasons. Always use the X-API-Key header.
Response structure
All endpoints return JSON with a consistent structure.
Collection response:
{
"data": [ ... ],
"meta": {
"total": 100,
"page": 1,
"limit": 20,
"pages": 5
}
} Single resource response:
{
"data": { ... }
} Errors
Error structure:
{
"error": true,
"message": "Error description",
"code": 401
} HTTP status codes used by the API:
| Code | Meaning |
|---|---|
200 | OK — The request was successful |
400 | Bad Request — Invalid or missing parameters |
401 | Unauthorized — Invalid or missing API Key |
403 | Forbidden — You don't have permission for this resource |
404 | Not Found — The resource does not exist |
422 | Unprocessable Entity — Invalid input data |
429 | Too Many Requests — You have exceeded the request limit |
500 | Internal Server Error — Server-side error |
Common parameters
Most public API endpoints accept these parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
web_id | string (UUID) | Yes | ID of the website you want to retrieve content from. Find it in Settings → Websites. |
lang | string | No | ISO language code (es, en, fr…). If omitted, returns the default language. |
page | integer | No | Page number for pagination. Default: 1. |
limit | integer | No | Results per page. Default: 20. Maximum: 100. |
Getting started
Integrating Ágora CMS into your project takes just a few minutes. You only need your API Key and the web_id of the site you want to connect. Follow these three steps:
- Get your API Key — log into the admin panel, go to Settings → API and copy your key. If you don't have one yet, click "Generate new key".
- Make your first request — test the posts endpoint with curl to verify authentication works:
curl "https://app.agorastack.com/api/v1/posts?web_id=YOUR_WEB_ID" -H "X-API-Key: YOUR_API_KEY" - Integrate into your frontend — use
fetch,axiosor any HTTP client. The examples in this documentation include ready-to-copy code.
Compatibility
The Ágora CMS API is a standard REST API that returns JSON. It is compatible with any technology that can make HTTP requests: Next.js (App Router and Pages Router), Astro with fetch at build time or SSR, Nuxt, standalone Vue, React, Svelte, mobile apps with React Native or Flutter, Python scripts with requests, PHP applications, or any automation with cURL.
There is no official SDK to install and no additional dependencies. If your environment can make a GET request with a custom header, you can use Ágora CMS.
Authentication in detail
Your API Key is a unique string per workspace. You can find it in Settings → API in the panel. Never expose it in client-side code served in the browser — always use it on the server (getStaticProps, server components, API endpoints, etc.).
You can rotate your API Key from the same panel at any time. When you rotate, the previous key becomes invalid immediately — make sure to update all integrations before doing so. If you think your key has been compromised, rotate it immediately: go to Settings → API → Rotate key.
In development environments you can use the same key as in production, or create a separate website in the panel to have isolated test data. There is no environment distinction at the API level — you manage the separation yourself through the web_id.
Rate limiting
The API applies a request limit per API Key to ensure service stability. When you exceed it, the server responds with 429 Too Many Requests and includes the Retry-After header indicating how many seconds to wait before retrying.
To handle rate limiting correctly, implement a retry mechanism with exponential backoff:
async function fetchWithRetry(url, options, retries = 3) {
for (let i = 0; i < retries; i++) {
const res = await fetch(url, options)
if (res.status !== 429) return res
const retryAfter = res.headers.get('Retry-After') || 2
await new Promise(r => setTimeout(r, retryAfter * 1000 * (i + 1)))
}
throw new Error('Too many retries')
} In projects with static builds (Astro, Next.js with SSG) the limit is rarely a problem because requests happen at compile time, not on every user visit. In SSR projects with heavy traffic, cache responses in memory or in Redis.
Pagination
Endpoints that return collections always include the meta object with pagination information:
"meta": {
"total": 87, // total records
"page": 1, // current page
"limit": 20, // records per page
"pages": 5 // total pages
}
To implement infinite scroll or load all results in sequence, use meta.pages as the stop condition:
async function fetchAllPosts(webId, apiKey) {
const base = 'https://app.agorastack.com/api/v1'
const headers = { 'X-API-Key': apiKey }
let page = 1
let all = []
while (true) {
const res = await fetch(
`${base}/posts?web_id=${webId}&page=${page}&limit=100`,
{ headers }
)
const { data, meta } = await res.json()
all = [...all, ...data]
if (page >= meta.pages) break
page++
}
return all
}
For infinite scroll in the frontend, store the current page in state and update the results array by concatenating each new load. Use meta.page < meta.pages to show or hide the "Load more" button.