Skip to content

Rate limits & errors

Limits are per route, over a rolling 60-second window, and are counted per client IP address rather than per key. Several keys behind one egress address share a bucket.

Route Limit per 60s
GET /api/v1/opportunities 60
GET /api/v1/opportunities/{id} 60
GET /api/v1/me 60
GET /api/v1/knowledge/docs 60
GET /api/v1/settings/notifications 60
GET /api/v1/settings/rules 60
GET /api/v1/profile 60
GET /api/v1/profile/changes 60
GET /api/v1/products 60
GET /api/v1/products/partners 60
GET /api/v1/products/import/template 60
POST /api/v1/session 30
POST /api/v1/opportunities/{id}/ask 20
POST /api/v1/opportunities/{id}/archive 10
DELETE /api/v1/opportunities/{id}/archive 10
POST /api/v1/opportunities/{id}/feedback 10
PATCH /api/v1/profile 10
POST /api/v1/profile/changes/{id}/revert 10
POST /api/v1/products 10
POST /api/v1/products/partners 10
PATCH /api/v1/products/{id} 10
POST /api/v1/products/import 10
GET /api/v1/api-keys 10
POST /api/v1/api-keys 10
DELETE /api/v1/api-keys/{id} 10
POST /api/v1/knowledge/docs 10
DELETE /api/v1/knowledge/docs/{id} 10
PATCH /api/v1/settings/notifications 10
PATCH /api/v1/settings/rules/{id} 10

GET /api/v1/scopes, GET /api/v1/openapi.json, and DELETE /api/v1/session carry no route limit.

Throttled routes report their budget on every response:

Header Meaning
x-ratelimit-limit The route’s maximum for the window.
x-ratelimit-remaining Requests left in the current window.
x-ratelimit-reset Seconds until the window resets.
retry-after Seconds to wait. Sent on a 429 only.

The request is rejected with 429 and this body:

{
"error": "rate_limited",
"message": "too many requests",
"requestId": "req-b"
}

Honour retry-after when it is present, and fall back to exponential backoff with jitter when it is not. Do not retry immediately in a tight loop. The window is rolling, so a burst of retries keeps the bucket empty and extends the lockout.

Every error from the API serializes to one shape, whether it is validation, auth, rate limiting, or an internal failure:

{
"error": "insufficient_scope",
"message": "this key lacks the opportunities:read scope",
"requestId": "req-4f2"
}
Field Type Notes
error string A stable code from the table below. Branch on this, never on message.
message string Human-readable detail. Wording may change; treat it as diagnostic text.
requestId string Identifies this specific request.
issues array Optional. Present on some validation failures, listing the specific problems.
Code Typical status Meaning
unauthorized 401 No credential presented, or the key is unknown, revoked, or expired.
forbidden 403 The credential is valid but not permitted to perform this action.
insufficient_scope 403 The key is missing a scope the route requires.
no_membership 403 The account is not linked to a company.
membership_disabled 403 The membership behind this credential has been disabled.
unverified_email 403 The signed-in account has not confirmed its email address.
identity_conflict 403 The membership is bound to a different identity.
validation_failed 400 The request was malformed: a bad parameter, body, or cursor.
not_found 404 No such resource for this company.
already_exists 409 The resource is already on file: a catalog product with this partner, name and model.
partner_not_authorized 409 The manufacturer partner has been removed from the company profile, so nothing can be added to its catalog until it is added back.
already_reverted 409 This profile change was reverted already.
superseded 409 The field has changed again since; this is no longer the latest change to it.
invalid_import 422 A CSV product import did not validate. Nothing was written; issues carries the first 50 problems and issue_count the true total.
rate_limited 429 The route’s limit for the window was exceeded.
internal 500 Something failed on our side. Safe to retry with backoff.

unauthorized, insufficient_scope, validation_failed, and not_found are the four an API-key integration will realistically encounter. The membership-related codes surface on browser sessions, not on key auth.

  • 429 and 5xx are transient. Retry with backoff.
  • 401 and 403 mean the credential itself is wrong. Retrying will not fix it; check the key and its scopes.
  • 400 and 404 mean the request is wrong. Retrying sends the same wrong request.