Paginating through large work order lists via API

Pagination behavior on GET /v1/work_orders appears inconsistent when result sets exceed 10k records. Observed:
  • Using page + per_page parameters
  • Records 9,001–10,000: returns as expected
  • Records 10,001+: duplicates from previous pages, gaps, or empty data array
No Link headers present in response. Documentation mentions cursor-based pagination but does not specify parameter names. Questions:
  1. Is offset pagination deprecated for large result sets?
  2. What are the exact cursor parameter names (cursor, after, start_after)?
  3. Is cursor value the id field or a separate token?
  4. Maximum per_page limit?
Tested with:
  • Account: ~45k work orders
  • per_page=100 (also tried 50, 200)
  • Endpoint: /v1/work_orders?status=completed&created_after=2024-01-01
Response structure does not include cursor in body. Example truncated response:
{
  "data": [...],
  "meta": {
    "total": 45231,
    "page": 100,
    "per_page": 100
  }
}
Parents
  • Yeah this one tripped me up too when I first looked at it — the docs are technically correct but buried the migration note three paragraphs deep. We moved to cursor pagination for result sets over 10k back in v1.8. The offset parameters still "work" but you'll hit eventual consistency issues at scale. Here's the actual implementation:
    GET /v1/work_orders?cursor=wo_abc123&per_page=100
    # or for first page:
    GET /v1/work_orders?per_page=100
    Key details:
    • Cursor parameter name is cursor (not after)
    • Value is the id of the last record from current page
    • Pass that as cursor for next page
    • When has_more: false, you're done
    Response body changes slightly:
    {
      "data": [...],
      "meta": {
        "cursor": "wo_abc123",
        "has_more": true,
        "per_page": 100
      }
    }
    per_page max is 500 for cursor pagination. The old total field isn't computed for cursors — intentional performance win, since counting 45k rows was part of the problem. I'll flag the docs for a clearer migration callout. Rate limits and pagination guide has more context.
Reply
  • Yeah this one tripped me up too when I first looked at it — the docs are technically correct but buried the migration note three paragraphs deep. We moved to cursor pagination for result sets over 10k back in v1.8. The offset parameters still "work" but you'll hit eventual consistency issues at scale. Here's the actual implementation:
    GET /v1/work_orders?cursor=wo_abc123&per_page=100
    # or for first page:
    GET /v1/work_orders?per_page=100
    Key details:
    • Cursor parameter name is cursor (not after)
    • Value is the id of the last record from current page
    • Pass that as cursor for next page
    • When has_more: false, you're done
    Response body changes slightly:
    {
      "data": [...],
      "meta": {
        "cursor": "wo_abc123",
        "has_more": true,
        "per_page": 100
      }
    }
    per_page max is 500 for cursor pagination. The old total field isn't computed for cursors — intentional performance win, since counting 45k rows was part of the problem. I'll flag the docs for a clearer migration callout. Rate limits and pagination guide has more context.
Children
No Data