Open dashboard

Guides

Rate limits & security

Understand the budgets, headers, and best practices for a reliable integration. Caps keep the scalpel useful for daily work — not full archive export.

Rate limits

Dual monthly budgets plus burst and daily caps. Exact remaining values are always on GET /stats.

3,000

Requests

per billing month · 1 per successful API call

3,000

Records

per billing month · 1 per row returned in list/dossier

CapTypical value
Per-minute burst20
Daily requests300
Monthly requests3,000
Monthly records3,000
Monthly page turns200
Daily company detail100 unique companies
Page size max50
Query set max500 (offset + pageSize bound)

Good to know

  • Only 2xx responses consume request/record budgets. Auth failures and validation errors do not.
  • Billing month follows the Stripe subscription period — not the calendar month.
  • Firehose delivery does not consume REST budgets.
  • On 429, read limitType and resetUnix before retrying.

Only successful requests are billed

4xx, 5xx, and 429 do not increment counters. Prefer backing off over tight retry loops.

Rate limit headers

Non-exempt successful responses include monthly request headers.

On every metered 2xx response

X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (unix), X-RateLimit-Policy: monthly_requests

On 429 (limit reached)

Body includes limitType, limit, used, remaining, resetUnix. Response also sets Retry-After (seconds).

Limit exceeded (429)

Example body when a daily request cap is hit:

429 JSON
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Daily request limit reached.",
    "status": 429,
    "limitType": "daily_requests",
    "limit": 300,
    "used": 300,
    "remaining": 0,
    "resetUnix": 1724198400
  }
}

Real-time usage: GET /api/v1/stats

Exempt from request budget. Use it to pace clients.

cURL
curl -s "${BASE_URL}/api/v1/stats" \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON (truncated)
{
  "period": { "monthStart": "…", "dayStart": "…" },
  "rateLimits": {
    "perMinute": { "limit": 20, "used": 0, "remaining": 20, "resetUnix": 0 },
    "dailyRequests": { "limit": 300, "used": 12, "remaining": 288, "resetUnix": 0 },
    "monthlyRequests": { "limit": 3000, "used": 40, "remaining": 2960, "resetUnix": 0 },
    "monthlyRecords": { "limit": 3000, "used": 100, "remaining": 2900, "resetUnix": 0 }
  },
  "staticLimits": { "pageSizeMax": 50, "querySetRecordsMax": 500 }
}

Exempt routes

RouteWhy
GET /api/v1/healthUptime / dependency check
GET /api/v1/statsBudget introspection

Best practices

Caching

Cache filter catalogs and dossiers briefly. Prefer firehose ids over re-searching.

Pagination

Keep pageSize ≤ 50. Deep pages cost page-turn quota.

Tight queries

Narrow signal_query and overlays before paging. Wide scans burn records fast.

Security

Store vs_ keys as secrets. Rotate if leaked. Use HTTPS in production.

See All endpoints for samples and Webhooks for the push path.

Rate limits — Pro API — VeilStrat | VeilStrat