Developer portal
Rate limits, idempotency, pagination, errors
The shared conventions every API route honours. Know these once and every endpoint behaves the same way.
Rate limits
Per API key. Limits refresh continuously (sliding window). On a 429, wait for the X-RateLimit-Reset epoch timestamp before retrying.
| Scope | Limit | Window |
|---|---|---|
| Default (per API key) | 300 requests | 1 minute |
| Bulk load endpoints | 10 concurrent | rolling |
| Webhook retries | 8 attempts over 24h | exponential backoff |
| Attachment uploads | 50 signed URLs | 1 minute |
| Export jobs | 5 concurrent per tenant | rolling |
Enterprise plans can negotiate higher limits; reach out to your CSM.
Idempotency
Supply an Idempotency-Key header on POST, PATCH, DELETE, or :transition requests. We store the response for 24 hours; retries return the cached response.
POST /api/v1/records
Authorization: Bearer ...
Idempotency-Key: 2a8c-4d3a-9f11-bulk-load-01
{ "moduleKey": "incidents", "payload": { ... } }Pagination
Cursor-based. Pass limit (max 200) and, on subsequent calls, cursor= the nextCursor returned previously.
GET /api/v1/records?moduleKey=inspections&limit=50&cursor=eyJpZCI6...Errors
RFC 7807 application/problem+json. Always include a code and traceId — paste the traceId into a support ticket to jump straight to logs.
{
"type": "https://qehsethos.com/errors/validation",
"title": "Validation failed",
"status": 400,
"detail": "Field 'severity' must be one of low|medium|high|critical",
"code": "field.invalid",
"traceId": "01J2H..."
}