Core concepts

Pagination and errors

How the Cooledge API paginates list endpoints with opaque cursors and how it reports errors. Covers the data and next_cursor envelope, the loop-until-null paging pattern and the RFC 7807 problem-details error format with its status codes.

Updated 17/06/2026

Pagination and errors

List endpoints return results a page at a time, and every error across the API follows one predictable shape. This guide covers both, so you can page through a full result set and read any error the same way wherever it comes from.

Cursor pagination

List endpoints use cursor pagination. Rather than asking for page 2 by number, you ask for the page that follows a cursor the previous response handed you. This keeps paging stable even when records are being created or changed while you read.

Two query parameters control a list request:

  • limit sets how many records you want in the page. The default is 25 and the maximum is 100. Ask for a limit outside the range one to 100, or a value that is not a whole number, and the request is rejected with a 400 whose detail reads limit must be an integer 1..100.
  • cursor asks for the page that follows a given position. You omit it on the first request and pass back the value the previous response gave you on each request after that.

The list envelope

Every list response is the same envelope: an array of records under data and a next_cursor field.

curl "https://app.cooledge.com.au/api/v1/customers?limit=2" \
  -H "X-Api-Key: ck_live_AB12CD_your_secret_here"
{
  "data": [
    { "id": "cust_5Gk9Rm2P", "name": "Jordan Avery" },
    { "id": "cust_7Hm2Tn8Q", "name": "Riley Quinn" }
  ],
  "next_cursor": "MjAyNi0wNi0xMlQwMTowNToxMnww..."
}

next_cursor is a string while there is more to fetch and null once you have reached the end. To get the next page, send the same request with that string as the cursor parameter:

curl "https://app.cooledge.com.au/api/v1/customers?limit=2&cursor=MjAyNi0wNi0xMlQwMTowNToxMnww..." \
  -H "X-Api-Key: ck_live_AB12CD_your_secret_here"

When you reach the final page, next_cursor comes back null:

{
  "data": [
    { "id": "cust_9Xw4Tn6V", "name": "Sam Okafor" }
  ],
  "next_cursor": null
}

Paging through everything

The pattern is the same on every list endpoint:

  1. Make the first request with no cursor. Set limit if you want a page size other than 25.
  2. Process the data array.
  3. If next_cursor is null, you are done.
  4. Otherwise make the same request again with cursor set to the next_cursor value, and repeat from step 2.

In words: keep passing the returned next_cursor back as cursor and loop until next_cursor is null.

Treat cursors as opaque

A cursor is opaque. It is an encoded token whose internal format is a Cooledge implementation detail. Do not parse it, decode it, build one yourself or assume it means anything. The only valid thing to do with a next_cursor is hand it straight back as the cursor on the next request. A cursor you have altered or constructed is rejected. Treating cursors as opaque also means your integration keeps working if the encoding changes.

Errors

Every error response across the API follows RFC 7807 problem details. The response has the content type application/problem+json and a JSON body with a small, fixed set of fields. Once you can read one error you can read them all, no matter which endpoint produced it.

{
  "type": "urn:cooledge:error:bad-request",
  "title": "Bad request",
  "status": 400,
  "detail": "limit must be an integer 1..100",
  "request_id": "3b1c0e2a-7d44-4e91-9a2c-1f0b8e6d5a23"
}

The fields are:

FieldAlways presentWhat it is
typeYesA stable URN identifying the error class, for example urn:cooledge:error:bad-request. Match on this rather than on the wording of title.
titleYesA short human-readable summary of the error class.
statusYesThe HTTP status code, repeated in the body so it is available even after the response is logged.
detailSometimesA message specific to this one occurrence, for example which field was wrong. Present when there is something useful to say.
request_idSometimesThe id of the request that failed. The same value is on the x-cooledge-request-id response header. Quote it when you contact support.

Status codes

These are the status codes the API uses for errors:

StatusMeaning
400Bad request. The request was malformed, for example an out-of-range limit or an invalid cursor.
401Unauthorized. The X-Api-Key header is missing, malformed or does not match a live key.
403Forbidden. The key is valid but not permitted: a missing scope or plan tier, or a lapsed subscription.
404Not found. No record matches, or the key cannot see it.
409Conflict. The request clashes with current state, for example a duplicate external id or a booking overlap.
422Unprocessable entity. The request was understood but cannot be carried out, for example sending to a customer with no email address on file.
429Too many requests. You exceeded the rate limit. See Rate limits for the Retry-After header and backoff.
500Internal server error. Something failed on our side. Retry with backoff and, if it persists, quote the request_id to support.

A note on the cases that are easy to confuse. 403 is about permission, not the credential itself: the key was recognised but the scope, the plan tier or the subscription state blocked it. See Authentication for the 401-versus-403 split. 409 signals a conflict with state that already exists, such as an external id you have already used or a booking that overlaps another. 422 means the request was well formed and understood but cannot proceed for a business reason, such as trying to send a quote to a customer who has no email address recorded.

Where to go next

  • Rate limits covers the 429 response, the Retry-After header and backoff guidance.
  • Authentication covers the scope list and how to read 401 and 403 errors.
  • The API reference lists the parameters and response shape for every endpoint.

Need a hand with an integration? Contact support