iAdvizeDocs

Errors and rate limits

The problem document every API error returns, the list of error codes, what causes each one, and how to handle rate limits.

Every error from /api/v1/ is an RFC 9457 problem document, served with the content type application/problem+json. The old { "error": "message" } body no longer exists. A client that parsed it needs to read code instead.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#not_found",
  "title": "Resource not found",
  "status": 404,
  "detail": "Site not found",
  "instance": "/api/v1/sites/site_01example",
  "code": "not_found",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11"
}
FieldTypeMeaning
typestringURL of the section below that describes this code.
titlestringShort summary of the code. The same for every error with that code.
statusnumberThe HTTP status, repeated from the response.
detailstringWhat went wrong on this request. Written for people; its wording can change at any time.
instancestringThe path of the request that failed.
codestringStable identifier of the error. Branch on this, never on detail.
requestIdstringQuote it when you contact support. It is the platform's request id when one is set, otherwise an opaque id starting req_.
errorsarrayOnly on some 400 responses: one entry per field at fault. See Field errors.

Codes are never renamed or reused. New codes can appear without a new API version, so treat an unknown code as a generic failure of its HTTP status.

Field errors

A validation error lists each offending field in errors. Each entry has a code and a detail, plus the location of the field:

  • pointer: an RFC 6901 JSON Pointer into the request body, for example /name. An empty pointer means the body as a whole.
  • parameter: the name of a query parameter, for example cursor.

An entry carries one of the two, depending on where the field is.

unauthorized

Status 401. The API key is missing, malformed, unknown, revoked or expired. The response is the same for all of these on purpose, so it never tells you which one it is.

What to do: check that the Authorization: Bearer <key> header is present and holds the full key. If the key was revoked or has expired, create a new one. Retrying the same request with the same key will not help.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#unauthorized",
  "title": "Missing or invalid API key",
  "status": 401,
  "detail": "Missing or invalid API key",
  "instance": "/api/v1/sites",
  "code": "unauthorized",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11"
}

invalid_request

Status 400. The request body or a query parameter failed validation. errors lists every field at fault.

What to do: fix the fields named in errors and send the request again. Do not retry it unchanged.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#invalid_request",
  "title": "Invalid request",
  "status": 400,
  "detail": "Too small: expected string to have >=1 characters",
  "instance": "/api/v1/sites",
  "code": "invalid_request",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11",
  "errors": [
    {
      "code": "too_small",
      "detail": "Too small: expected string to have >=1 characters",
      "pointer": "/name"
    }
  ]
}

invalid_cursor

Status 400. A pagination cursor was not one the API issued, or was altered. The entry in errors names the cursor parameter.

What to do: pass back the cursor exactly as the previous response returned it, or start again from the first page.

GET /api/v1/sites/{siteId}/conversations is the endpoint that takes a cursor today, so it is the one that can return this code. See Filter and paginate conversations.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#invalid_cursor",
  "title": "Invalid cursor",
  "status": 400,
  "detail": "Invalid cursor",
  "instance": "/api/v1/sites/site_01example/conversations",
  "code": "invalid_cursor",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11",
  "errors": [
    {
      "code": "invalid_cursor",
      "detail": "Invalid cursor",
      "parameter": "cursor"
    }
  ]
}

cursor_mismatch

Status 400. The cursor is one the API issued, but for a different set of filters than the ones on this request. A cursor marks a position in one specific listing. The entry in errors names the cursor parameter.

What to do: to read the next page, send the same filters as the request that returned the cursor. To change a filter, start again without a cursor. Changing limit or count between pages is fine, since neither is part of the listing.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#cursor_mismatch",
  "title": "Cursor does not match the filters",
  "status": 400,
  "detail": "This cursor was issued for different filters. Start again without a cursor to change the filters.",
  "instance": "/api/v1/sites/site_01example/conversations",
  "code": "cursor_mismatch",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11",
  "errors": [
    {
      "code": "cursor_mismatch",
      "detail": "This cursor was issued for different filters. Start again without a cursor to change the filters.",
      "parameter": "cursor"
    }
  ]
}

invalid_filter

Status 400. The filter is well-formed but the API refuses it as a whole. The entry in errors names the parameter at fault. Three cases:

  • A label token that the taxonomy does not define, in labels.all, labels.any or labels.none. Read the valid tokens from GET /api/v1/labels/vocabulary.
  • A labels.none filter with nothing to narrow the listing first: it needs labels.all, labels.any, from or to alongside it. labels.none also accepts only tokens that end in :true.
  • A labelStatus other than labeled combined with a labels.* or score filter, since only labeled conversations have labels. The entry names labelStatus.

What to do: fix the parameter named in errors and send the request again. Do not retry it unchanged.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#invalid_filter",
  "title": "Invalid filter",
  "status": 400,
  "detail": "unknown label or value for taxonomy v1.1",
  "instance": "/api/v1/sites/site_01example/conversations",
  "code": "invalid_filter",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11",
  "errors": [
    {
      "code": "invalid_filter",
      "detail": "unknown label or value for taxonomy v1.1",
      "parameter": "labels.all"
    }
  ]
}

A parameter the endpoint does not define, or a single-valued parameter sent twice, is an invalid_request, not an invalid_filter. Its errors entry has the code unknown_parameter or duplicate_parameter.

not_found

Status 404. The resource does not exist, or it is not visible to your organization. A resource that belongs to another organization, was deleted, or sits under a different site reads exactly like one that never existed. A path that no route serves also gets this code.

What to do: check the ids in the path. Ids are opaque strings, so use them as the API returned them. A missing resource will not appear by retrying.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#not_found",
  "title": "Resource not found",
  "status": 404,
  "detail": "Site not found",
  "instance": "/api/v1/sites/site_01example",
  "code": "not_found",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11"
}

A method that an existing path does not support (a POST on a read-only path, say) is answered by the framework with a plain 405, not a problem document.

last_site

Status 409. The request conflicts with the current state of the resource. Today the only case is DELETE /api/v1/sites/{siteId} on the only site of your organization. An organization keeps at least one site. Nothing was changed.

What to do: create another site, then delete this one. Retrying the same request without adding a site will fail the same way.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#last_site",
  "title": "An organization keeps at least one site",
  "status": 409,
  "detail": "An organization keeps at least one site",
  "instance": "/api/v1/sites/site_01example",
  "code": "last_site",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11"
}

rate_limited

Status 429. You sent too many requests. The response carries a Retry-After header with the number of seconds to wait.

What to do: stop sending requests for Retry-After seconds, then retry. Do not retry in a tight loop. See Rate limits.

HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 60
{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#rate_limited",
  "title": "Too many requests",
  "status": 429,
  "detail": "Too many requests. Wait before retrying.",
  "instance": "/api/v1/sites",
  "code": "rate_limited",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11"
}

internal_error

Status 500. Something failed on our side. The detail is always generic and never contains an internal message.

What to do: retry a GET after a short delay, with the delay growing on each attempt. Before retrying a POST, PATCH or DELETE, read the resource to check whether the first attempt went through. If the error persists, contact support and quote the requestId.

{
  "type": "https://www.iadvize.ninja/docs/product/api-errors#internal_error",
  "title": "Internal server error",
  "status": 500,
  "detail": "An unexpected error occurred.",
  "instance": "/api/v1/sites",
  "code": "internal_error",
  "requestId": "req_2f6c1d5e-7a7e-4f4b-9b39-1d1c8a7f0c11"
}

Rate limits

Two limits apply, and both are checked before your API key is validated:

  • Per API key. Requests sent with the same key share one allowance.
  • Per client address. Requests from the same IP address share one allowance, whatever key they use.

Both are counted over a 60-second window. The API reference intro currently states 600 requests per minute per key and 1200 requests per minute per client address. Those figures are starting values and can change without a new API version. Do not hard-code them: read the Retry-After header of a 429 and wait that many seconds. The API currently always answers 60.

The address limit is checked first, so a burst of requests from one address can get a 429 even when your key is well under its own limit.

API changes within v1

The API is additive within /v1. New fields, new error codes and new message block types can appear without a new version. Write clients that ignore fields, codes and block types they do not know.

On this page