code inside the body tells you exactly what happened.
The error envelope
Every error response has the same body:string
required
The stable machine value. Branch on this.
string
required
A sentence for people. The wording can change, so never match on it.
object | array
Extra data for some codes: the fields that failed validation, the id of the resource that already exists, the numbers behind a plan limit. Its shape depends on
code. Treat it as optional, even on a code that normally carries it.string
required
The id of this request. It equals the
X-Request-Id response header.409 alone covers many different situations. Always branch on error.code.
Request ids
Every response carries anX-Request-Id header, whether it succeeded or failed. On an error, the same value is request_id in the body.
Log the request id with every call you make. When you contact support, quote it. It lets us find the exact request.
Validation errors
400 validation_error means a query parameter, a header or a body field failed validation. details is a list with one entry per problem:
string
The field that failed. Nested fields are joined with dots, as in
competitors.0.domain. For a header it is the header’s name, as in Idempotency-Key. It can be empty when the problem is the body as a whole, and it names the pair from/to for invalid_date. Branch on code; use path for display.string
What was wrong with it.
string
The same, as a sentence.
Other checks report a generic code for the kind of rule that failed, such as
too_big for a limit over the maximum. Webhook endpoint and subscription requests add field-level codes of their own, such as url_not_public. Rely on path and on the codes above.
Pagination and date windows covers the three window codes.
When part of a write happened
On the partial provisioning responses,details has three fields:
string
The id of the own brand that was created.
object
The created property, in the same shape as
data in the 201 response.array
One entry per competitor domain you sent, each with
name, domain and a status: applied, failed or not_attempted. An applied entry carries competitor_id and reused. A failed entry carries error with its own code and message. not_attempted means an earlier competitor hit the plan limit, so this one was never tried.409 brand_exists, 409 external_ref_exists, 422 country_cap_exceeded and 422 brand_cap_exceeded.
Error codes by status
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
409 Conflict
Inside a prompt sync,
prompt_writes_busy is reported per row, as one failed result in the 200.
413 Payload Too Large
422 Unprocessable Entity
A plan limit refused the write.details can carry tier, cap and attempted. Every one of those fields is optional.
Read
usage on GET /orgs/{orgId} to see what is used against the prompt, own-brand and country limits, and the per-brand competitor limit, before you write. Only active prompts count, so deactivating a prompt frees its place. Plans and limits lists the limits by plan.
429 Too Many Requests
Both codes carryRetry-After. See Rate limits and quotas.
500 Internal Server Error
503 Service Unavailable
Every503 carries Retry-After.
Which errors to retry
One
400 has an automatic remedy: on invalid_cursor, start the walk again from the first page.
A 5xx on a write does not tell you whether the write was applied. Provisioning a property and syncing prompts apply their rows one at a time, so a failure part-way leaves the earlier rows in place. Send an Idempotency-Key with every write, and after a timeout or a 5xx retry with the same key. A create that did land the first time then answers 409 with the id of the existing resource. See Idempotent requests.
Request bodies
Writes take a JSON body of at most 1 MB. A larger body answers413 payload_too_large, malformed JSON answers 400 invalid_json, and a body on a GET answers 400 body_not_allowed.
Unknown body fields are ignored, with two documented exceptions. text on PATCH /orgs/{orgId}/prompts/{promptId} answers 400 text_immutable. The bodies of POST /webhook-endpoints and POST /webhook-endpoints/{endpointId}/subscriptions are strict, so an unknown field there answers 400 validation_error.
A request body must arrive in full within 10 seconds. After that the connection is closed without a response.
Handling errors in code
Read the envelope once, keep thecode, the details and the request id, and branch on the code.