Browse all docs
API Reference

Rate Limits and Pagination

5 min read

Rate Limits and Pagination

Every production integration eventually hits two walls: request quotas and large result sets. This guide explains exactly how Loomstack enforces rate limits, how to build clients that never trip them, and how to page through collections efficiently.

Rate Limit Tiers

Limits apply per API key, measured over a sliding 60-second window:

PlanRequests/minuteBurst
Pro1,000100/sec
Business5,000250/sec
EnterpriseCustomCustom

A few endpoints carry stricter sub-limits regardless of plan: task creation (POST /v1/projects/{projectId}/tasks) at 100/minute, and invites (POST /v1/users/invite) at 20/minute. Batch endpoints count as a single request, which is why they’re strongly preferred for bulk work.

Reading the Rate Limit Headers

Every response includes your current standing:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 741
X-RateLimit-Reset: 1758809011
  • X-RateLimit-Remaining — requests left in the current window
  • X-RateLimit-Reset — Unix timestamp when the window refills

Well-behaved clients check Remaining proactively and slow down before hitting zero, rather than reacting to errors.

Handling 429 Responses

When you exceed the limit, the API returns 429 with code RATE_LIMIT_EXCEEDED and a Retry-After header (seconds):

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Retry after 12 seconds."
  }
}

The correct client behavior:

  1. Honor Retry-After exactly — do not retry sooner
  2. Add jitter when multiple workers share a key, so they don’t retry in lockstep
  3. Use exponential backoff for repeated 429s: wait Retry-After, then 2×, then 4×
  4. Never spread traffic across multiple keys to dodge limits — it violates the API terms and Enterprise customers can simply request higher limits

Offset Pagination

List endpoints accept limit (default 50, max 100) and offset:

curl "https://api.loomstack.com/v1/projects/proj_884/tasks?limit=100&offset=200" \
  -H "Authorization: Bearer YOUR_API_KEY"

Responses include a meta block:

{
  "success": true,
  "data": [ ... ],
  "meta": { "total": 1342, "limit": 100, "offset": 200 }
}

Offset pagination is fine for small, stable collections, but it can skip or duplicate items if tasks are created or deleted between pages.

Cursor Pagination

For large or frequently changing collections, use cursors — pass cursor instead of offset:

curl "https://api.loomstack.com/v1/projects/proj_884/tasks?limit=100&cursor=cur_eyJpZCI6..." \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "success": true,
  "data": [ ... ],
  "meta": {
    "next_cursor": "cur_eyJpZCI6IjEwMjQifQ",
    "has_more": true
  }
}

Loop until has_more is false. Cursors are stable across inserts and deletes, expire after 15 minutes of inactivity, and are opaque — never parse or construct them yourself.

Efficiency Checklist

  • Request only what you need with fields: ?fields=id,title,state cuts payload size dramatically
  • Use updated_since on list endpoints for incremental syncs instead of re-fetching everything
  • Prefer webhooks over polling for change detection
  • Cache stable lookups (project IDs, user IDs) — they rarely change

Summary

Watch X-RateLimit-Remaining and honor Retry-After with jittered exponential backoff on 429. Use offset pagination for quick scripts, cursor pagination (next_cursor / has_more) for anything large or live, and combine fields, updated_since, and webhooks to keep your request volume far below the limit in the first place.

Was this helpful?