Handle rate limits and pagination
Coris API rate limits, concurrency limits, 429 handling, and offset and cursor pagination for list endpoints.
The standard limit is 1,000 requests per minute, per user. Page through lists with limit and offset, or with cursors on the accounts list.
- StartGET /
accounts/ ? limit=50& sort_by=created& sort_order=desc - ReturnsPage of accounts
- CheckMore?
- YesGET /
accounts/ ? limit=50& sort_by=created& sort_order=desc& after_id=<last id> - NoDone
Over limit: 429
Page through a list
- Set your base URL and API key.
export CORIS_BASE_URL="https://sandbox-api.coris.ai/api/v0_2"
export CORIS_API_KEY="YOUR_API_KEY"import requests
BASE_URL = "https://sandbox-api.coris.ai/api/v0_2"
HEADERS = {"Authorization": "Token YOUR_API_KEY"}const BASE_URL = "https://sandbox-api.coris.ai/api/v0_2";
const HEADERS = {
Authorization: "Token YOUR_API_KEY",
"Content-Type": "application/json",
};- Fetch a page with totals. With metadata, the body is an object, not a plain array.
curl -s "$CORIS_BASE_URL/accounts/?limit=50&return_pagination_metadata=true" \
-H "Authorization: Token $CORIS_API_KEY" | jq '.pagination_metadata.total'page = requests.get(
f"{BASE_URL}/accounts/",
params={"limit": 50, "return_pagination_metadata": "true"},
headers=HEADERS,
).json()
print(page["pagination_metadata"]["total"], len(page["data"]))const pageResponse = await fetch(
`${BASE_URL}/accounts/?limit=50&return_pagination_metadata=true`,
{ headers: HEADERS },
);
const page = await pageResponse.json();
console.log(page.pagination_metadata.total, page.data.length);Try GET /accounts/ in the API explorer.
{
"pagination_metadata": { "total": 142 },
"data": [
{ "id": "c47f0e21-6a9b-4d38-a2e5-1b8d3f90c6a7", "reference_id": "acme-plumbing-001" }
]
}pagination_metadata.total counts the items matching your filters, and can change during writes.
- Walk the list with cursors, which suit large exports. Send
sort_by=created&sort_order=descon every request, and use the lastidon each page asafter_id.
AFTER=""
while : ; do
PAGE=$(curl -s "$CORIS_BASE_URL/accounts/?limit=50&sort_by=created&sort_order=desc${AFTER:+&after_id=$AFTER}" \
-H "Authorization: Token $CORIS_API_KEY")
[ "$(printf '%s' "$PAGE" | jq 'length')" = "0" ] && break
printf '%s' "$PAGE" | jq -r '.[].id'
AFTER=$(printf '%s' "$PAGE" | jq -r '.[-1].id')
doneaccounts, after_id = [], None
while True:
params = {"limit": 50, "sort_by": "created", "sort_order": "desc"}
if after_id:
params["after_id"] = after_id
rows = requests.get(f"{BASE_URL}/accounts/", params=params, headers=HEADERS).json()
if not rows:
break
accounts.extend(rows)
after_id = rows[-1]["id"]
print(len(accounts))const accounts = [];
let afterId = null;
while (true) {
const query = new URLSearchParams({ limit: "50", sort_by: "created", sort_order: "desc" });
if (afterId) query.set("after_id", afterId);
const rows = await (await fetch(`${BASE_URL}/accounts/?${query}`, { headers: HEADERS })).json();
if (rows.length === 0) break;
accounts.push(...rows);
afterId = rows[rows.length - 1].id;
}
console.log(accounts.length);Cursor rules:
- A first page with no
sort_byhas no set order, so rows repeat or go missing. before_id,after_idandoffsetcannot be combined.- An invalid cursor returns
400.
Pagination parameters
| Parameter | Meaning | Default |
|---|---|---|
limit | Items per page. | 10 |
offset | Items to skip. | 0 |
after | Items created after this epoch time. | None |
before | Items created before this epoch time. | None |
return_pagination_metadata | Send any value, even false, to get the object above. Leave it out to get a plain array. | Off |
These lists ignore limit and return every row: /account_tags/, /settings/custom_list/, /accounts/{account_id}/persons/, /accounts/{account_id}/websites/ and /accounts/{account_id}/metadata/.
Rate limits
| Limit | Value | Applies to |
|---|---|---|
| Authenticated requests | 1,000 per minute, per user | Endpoints using the standard throttle |
| Concurrent synchronous data requests | 25 by default, per workspace | GET requests that fetch data live |
POST requests and GET requests with request_id skip the concurrency limit, so use the async flow for bulk work.
What to do next
| Situation | Action |
|---|---|
429 with Retry-After | Wait that many seconds, then retry. |
429 with no Retry-After | You hit the concurrency limit. Back off for a few seconds and reduce parallel calls. |
| Your workload needs more concurrency | Ask for a higher limit. |
FAQ
What is the maximum limit?
limit?Most lists enforce no maximum, but stay near 100 so that responses stay fast.
Do all lists support cursors?
No. Only the accounts list uses them. Other lists use offset.
Should I fetch pages in parallel?
No. Fetch them in order, which also keeps your results consistent.
Next: Track API versions
Updated about 23 hours ago