Pagination

Every /v1 list is:

{
  "<name>": [ ],
  "page": {
    "number": 1,
    "has_more": true,
    "limit": 50
  }
}

There is no total. page.number is the page you asked for. Keep going while page.has_more is true.

Walk pages

Used on GET /v1/projects (verify:read):

curl -s "https://api-arbitr.straker.ai/v1/projects?page=1&limit=50" \
  -H "X-API-Key: abr_live_…"
page_number = 1
projects = []
while True:
    r = client.get("/v1/projects", params={"page": page_number, "limit": 50})
    body = r.json()
    projects.extend(body["projects"])
    if not body["page"]["has_more"]:
        break
    page_number += 1

If you need a count for a UI, walk until has_more is false, or skip the count and sync incrementally with modified_after.

GET /v1/projects query params

Only these are accepted. Anything else — cursor, sort, search, page_size — returns 400 validation_failed and names the parameter.

Param Type Default Notes
page int, 1–100000 1 1-based
limit int, 1–200 50 Items per page
status string omit One status, e.g. completed
modified_after ISO 8601 omit updated_at >= this time

Incremental sync: store the highest updated_at you have seen, send it as modified_after next time.

Full lists

GET /v1/languages and GET /v1/projects/{id}/deliverables still use the same envelope, but return everything in one page:

{
  "number": 1,
  "has_more": false,
  "limit": 12
}

limit here is the length of the array, not a query param you send.