Skip to main content
When a request fails, Conduit returns a JSON body with a stable, machine-readable error code and the same request identifier you would get on success. You can branch on error.code programmatically and quote request_id when you contact support. This page covers the error envelope, the full code table, the fail-closed behavior on unknown parameters, and how to use the request identifier.

The error envelope

Errors mirror the success envelope: an error object replaces data, and the request identifier is preserved at both the top level and inside error.
{
  "error": {
    "code": "bad_request",
    "message": "Unknown query parameter: 'contry'",
    "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55",
    "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55",
    "details": {}
  },
  "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55"
}
error
object
required
The error payload. Present instead of data on any failed request.
requestId
string
required
The request identifier, repeated at the envelope root. Identical to error.request_id.

Error codes

Codes are stable. The HTTP status always matches the code as listed here.
CodeHTTP statusMeaning
bad_request400The request was malformed: an invalid value, a missing required field, or an unknown query parameter.
unauthorized401No API key was provided, or the key is invalid. Send a valid key via x-api-key or Authorization: Bearer.
forbidden403The key is valid but lacks the scope required for the route (for example, calling an ops:read route with a data:read key).
not_found404The requested resource does not exist (for example, an unknown entity, observation, or event id).
rate_limited429You exceeded the rate limit for your client and scope in the current window. See Rate limits.
internal_error500An unexpected server error. Retry with backoff; if it persists, contact support with the request_id.
Branch your error handling on error.code, never on the HTTP status alone and never on the message string. The code is the part of the contract that is guaranteed stable.

Fail closed on unknown parameters

Conduit rejects unknown query parameters rather than silently ignoring them. If you send a parameter the endpoint does not recognize (for example, a typo like contry instead of country), the request fails with bad_request and a 400 status. This is deliberate. Silently ignoring a misspelled filter would return data that does not match what you asked for, which is worse than a clear error. Fail-closed means a typo surfaces immediately instead of quietly returning the wrong rows.
A typo fails closed (cURL)
curl -s "https://data.quantoraresearch.com/v1/public/observations?contry=USA" \
  -H "x-api-key: $CONDUIT_API_KEY"
# -> 400 bad_request: Unknown query parameter: 'contry'
Check parameter spelling against the OpenAPI spec when you get an unexpected bad_request. A rejected unknown parameter is the most common cause.

Handling errors in code

import os
import requests

resp = requests.get(
    "https://data.quantoraresearch.com/v1/public/observations",
    headers={"x-api-key": os.environ["CONDUIT_API_KEY"]},
    params={"country": "USA", "indicator": "cpi_inflation_yoy"},
)

if not resp.ok:
    err = resp.json()["error"]
    print(f"[{err['code']}] {err['message']} (request_id={err['request_id']})")
    # branch on err["code"]: "rate_limited", "unauthorized", "bad_request", ...
else:
    data = resp.json()["data"]

Using request_id with support

Every error response carries a request_id (and its requestId twin). The value identifies your exact request in the server logs. When something looks wrong and you reach out for help, include:
  • the request_id from the failing response,
  • the error.code you received,
  • the full URL you called (with parameters).
That triple lets support locate your request immediately, without guesswork.

Rate limits

The 429 body, the limit headers, and backoff guidance.

Response envelope

How errors mirror the success envelope.