Limits, errors and versioning
The numbers and shapes you build retry logic around.
Rate limits
| Surface | Limit | Keyed by |
|---|---|---|
| Any API key (Inbound API and Installer API v1) | 60 requests / minute | Each key |
| Any API key | 300 requests / minute | Key owner: the company or installer company, all its keys together |
Inbound API network guard (/inbound) | 600 requests / minute | Source IP address |
| Health and version endpoints | 3,000 requests / minute | Source IP address |
Exceeding a limit returns 429 with a retry-after header in seconds; the network guards also send the standard RateLimit headers. Back off for at least that long, with jitter. Sustained 429s from one key are visible to us and we will reach out before disabling anything. Higher limits for the Installer API are available for companies that batch through cursor pagination rather than polling individual jobs.
Polling guidance
- Prefer webhooks; poll the Installer API's change feed (
GET /partner/v1/jobs?cursor=) no more than once a minute as a safety net. - Keep the last
nextCursor; a request without a cursor returns the most recent page, not everything. - Do not fetch every job by id after each list; the list already carries the full safe resource.
Error shape
HTTP/1.1 409 Conflict
content-type: application/json
x-request-id: 7f3c…
{ "error": "Job changed; current version is 8" }
| Status | Meaning | What to do |
|---|---|---|
| 400 | Validation failed; message names the field | Fix the request; do not retry unchanged |
| 401 | Missing, malformed, revoked or wrong-surface key | Check the header and key kind; rotate if unsure |
| 403 | Key lacks a scope, or the resource is outside your boundary | Request the right key kind; never work around by another route |
| 404 | Resource not visible to this key | Treat like 403; existence is not confirmed either way |
| 409 | Idempotency-Key reused with a different body, or expectedVersion is stale | Re-read the resource and resubmit with the current version and a new key |
| 422 | Semantically invalid (e.g. status transition not allowed) | Read the message; adjust state machine |
| 429 | Rate limited | Honour retry-after |
| 5xx | Our fault | Retry with backoff and the same Idempotency-Key |
Always log x-request-id; it is the fastest way for us to find your request in our traces.
Idempotency
- Inbound appointments carry
idempotencyKeyin the body (8 to 160 characters). Installer API writes carry anIdempotency-Keyheader (up to 128 characters: letters, digits,. _ : -). - A replay with the same key and same body returns the original result. Same key with a different body or different operation returns 409.
- Keys are scoped to your key owner; you cannot collide with another partner.
- Use a UUID per logical operation and persist it before sending, so a crash between send and ack still replays correctly.
Time
All timestamps are ISO-8601 in UTC with a Z suffix. Installer status events accept occurredAt up to 5 minutes in the future and 30 days in the past. Schedules include an IANA time zone name so the crew's local day is unambiguous.
Versioning and deprecation
- The Installer API is versioned by date. The current version,
2026-08-26, is returned inx-ridge-arc-api-versionand in every webhook envelope'sapiVersion. - Additive changes (new fields, new events, new optional parameters) ship without a version change. Ignore fields you do not know.
- Breaking changes ship as a new date. The previous date keeps working for at least 90 days after the new one is announced on the changelog and by email to your technical contact.
- Webhook payloads carry
schemaVersion; a breaking payload change increments it and is delivered only to subscriptions that have opted in. - Sandbox receives changes at least two weeks before production.
Payload limits
| Item | Limit |
|---|---|
| Request body | 1 MB |
| Inbound lead fields | fullName 120, email 254, phone 40, address 500 characters |
| Appointment notes | 500 characters |
| Contractor job status note | 2,000 characters |
| List page size | Installer API 1 to 100 (default 50); inbound jobs 1 to 200 (default 50) |
| Webhook response wait | 10 seconds |