Skip to main content
Every error response carries a code, and its doc_url links to that code on this page. Branch on code, never on message. The errors guide covers the error format and how to handle errors in code. Codes are a stable contract: we add new ones and never rename or repurpose one. If you meet a code that isn’t listed here, handle it by its type and HTTP status.

400 and 422: the request

INVALID_REQUEST

400 Bad Request · type invalid_request · Open page The request as a whole was refused before we read it, today only because the body is over 2 MB. When it happens The request body is larger than 2 MB, judged by its Content-Length header or by what actually arrived. A quote with 25 policies and every field at its longest is about 1.3 MB, so a real request shouldn’t come close. What to do Check that you aren’t sending something you didn’t mean to, such as an encoded document. Don’t retry the same request.

INVALID_JSON

400 Bad Request · type invalid_request · Open page The request body isn’t valid JSON. When it happens The body of a POST couldn’t be parsed as JSON: a trailing comma, a single-quoted string, or a body built by string concatenation. (An empty body is read as {} and then fails validation instead.) What to do Serialize the body with your language’s JSON library, and send Content-Type: application/json.

VALIDATION_FAILED

422 Unprocessable Entity · type invalid_request · Open page The body is valid JSON but breaks the endpoint’s rules. details lists every problem at once. When it happens One or more fields are missing, have the wrong type or format, are out of range, or aren’t fields at all. POST /v1/quotes checks the whole body and reports every problem in details, each with its own code, param and message; the top-level param and message describe the first. Common causes:
  • money sent as a JSON number (46100) instead of a string ("46100.00");
  • a rate sent as a percentage (25) instead of a fraction (0.25);
  • insured.address.state that isn’t a two-letter USPS state code (detail code INVALID_FORMAT). A full state name gets Use the two-letter state code, e.g. "TX" for Texas.; anything else gets Must be a two-letter US state code, e.g. "TX". A valid code for a state outside the program isn’t an error: it’s a 201 ineligible quote;
  • minimum_earned with both or neither of rate and amount;
  • a coverage type that isn’t on the list, or a misspelled field name;
  • a blank broker_email;
  • more than 25 policies (one TOO_MANY detail, before anything else is checked).
What to do Fix each field named in details and send the request again. A request that fails validation never uses up its Idempotency-Key, so you can reuse the key. It does count toward your rate limits, so don’t retry it unchanged.

INVALID_API_VERSION

400 Bad Request · type invalid_request · Open page The Bridgeline-Version header isn’t a real date in YYYY-MM-DD form. When it happens You sent a Bridgeline-Version header that isn’t a valid calendar date, such as 2026-9-23, v1 or 2026-02-30. What to do Send Bridgeline-Version: 2026-09-23, or leave the header out to use the current version. See versioning.

IDEMPOTENCY_KEY_INVALID

400 Bad Request · type invalid_request · Open page The Idempotency-Key header isn’t 1 to 255 printable ASCII characters. When it happens The Idempotency-Key header is empty, longer than 255 characters, or contains characters outside printable ASCII. What to do Use a UUID v4 (36 characters). See idempotency.

IDEMPOTENCY_KEY_REQUIRED

400 Bad Request · type invalid_request · Open page This endpoint requires an Idempotency-Key header. No current endpoint does. When it happens Reserved for endpoints where a duplicate would matter most, such as ones that send documents to a borrower. No endpoint available today requires a key, so you won’t see this code yet. What to do Send an Idempotency-Key on every write now, and you’ll never see it. See idempotency.

INVALID_PAGINATION

400 Bad Request · type invalid_request · Open page A list request’s limit isn’t a whole number from 1 to 100. No list endpoint exists yet. When it happens Reserved for list endpoints, which take limit (1 to 100, default 20) and starting_after. No list endpoint is available today, so you won’t see this code yet. What to do When list endpoints ship, send a limit between 1 and 100.

401: the key

INVALID_API_KEY

401 Unauthorized · type authentication · Open page The API key is missing, malformed or not recognized. When it happens
  • There’s no Authorization header, or it doesn’t start with Bearer .
  • The key is truncated or mistyped. Every key carries a checksum, so a typo is caught straight away.
  • The key doesn’t exist, or its prefix doesn’t match its mode.
What to do Check you’re sending the whole key, exactly as it was shown when it was created, as Authorization: Bearer bl_live_.... A lost key can’t be recovered: an agency admin can revoke it and create a new one under API Keys in the portal.

KEY_REVOKED

401 Unauthorized · type authentication · Open page The API key has been revoked. When it happens An agency admin revoked this key in the portal. Revocation is immediate and permanent. What to do Ask an agency admin to create a new key under API Keys in the portal, and replace the old one in your secret store.

KEY_EXPIRED

401 Unauthorized · type authentication · Open page The API key has passed its expiry date. When it happens The key was created with an expiry date, and that date has passed. What to do Ask an agency admin to create a new key. To rotate without downtime, create the new key before the old one expires; a key can be used alongside another.

403: permission

API_ACCESS_NOT_ENABLED

403 Forbidden · type permission · Open page API access isn’t turned on for your agency. When it happens Bridgeline hasn’t enabled API access for your agency yet, or it has been turned off. During the beta, API access is by invitation. When it’s off, every key your agency holds gets this answer. What to do Contact your Bridgeline contact. Links to interactive quotes you’ve already sent keep working while access is off; see links outlive API access.

MISSING_SCOPE

403 Forbidden · type permission · Open page The API key lacks a scope this endpoint needs. When it happens The endpoint needs a scope the key wasn’t given, for example quotes:write to create a quote. The message names the missing scopes. What to do Scopes are set when a key is created. Ask an agency admin to create a key with the scopes you need, then revoke the old one. See scopes.

BROKER_NOT_ACTIVE

403 Forbidden · type permission · Open page The broker_email you sent isn’t an active broker at your agency. When it happens You named a broker in broker_email, and they aren’t an active broker at the key’s agency. We give the same answer whether they’re inactive, invited but not yet active, or at another agency. What to do Check the email matches the broker’s login in the Bridgeline portal. If they’re new, an agency admin can invite or activate them there. Or leave broker_email out to act as the key’s default broker.

ACTING_BROKER_NOT_ALLOWED

403 Forbidden · type permission · Open page A broker key can only act as its own broker. When it happens The request came from a broker key and named a different broker in broker_email. What to do Leave broker_email out, or use an agency key, which can act as any active broker at your agency. See key types.

DEFAULT_BROKER_INACTIVE

403 Forbidden · type permission · Open page The API key’s default broker is no longer active. When it happens The broker this key acts as by default has been deactivated, and the request didn’t name another broker. Reads always use the default broker, so they fail too. We never move a request to someone else silently. What to do Ask an agency admin to create a new key with an active default broker. With an agency key, a write can also name an active broker in broker_email.

TEST_MODE_NOT_ENABLED

403 Forbidden · type permission · Open page Test mode isn’t turned on for your agency, so its test keys are refused. When it happens You used a test key (bl_test_), and test mode isn’t enabled for your agency, or has been turned off. Bridgeline enables test mode agency by agency. An agency admin who tries to create a test key in the portal gets the same answer. Test mode is enabled separately from live API access: this code is only ever about test keys, and your live keys keep working either way. What to do Ask your Bridgeline contact to enable test mode for your agency. See test and live mode.

TEST_MODE_ONLY

403 Forbidden · type permission · Open page A test helper was called with a live key. Test helpers need a test key. When it happens You called a test helper, an endpoint under /v1/test_helpers/, with a live key (bl_live_). Test helpers act out what a person would do, such as your client tapping I’m interested, so they only work on test data, with a test key. What to do Call it with a test key (bl_test_), on a quote that key created. See test and live mode.

404, 405 and 409

NOT_FOUND

404 Not Found · type not_found · Open page There’s no object with this id that your key can see. When it happens The id is malformed, doesn’t exist, or belongs to something your key can’t see. All of these get the same answer, so an id never reveals whether a deal exists elsewhere:
  • a quote from another agency;
  • a quote in the other mode (a test key reading a live quote, or the reverse);
  • a colleague’s quote, read with a broker key, which sees only its own broker’s quotes.
What to do Check the id (quote ids start with qte_ and are 26 characters), and that the key is the right mode and type. An agency key can see every quote in the agency.

METHOD_NOT_ALLOWED

405 Method Not Allowed · type invalid_request · Open page The endpoint exists, but not with this HTTP method. When it happens Reserved. Today, a request with an unsupported method on an existing path gets a 405 with no JSON body rather than this error. What to do Check the method against the API reference: POST to create, GET to read.

QUOTE_EXPIRED

409 Conflict · type conflict · Open page The quote is past its expires_at, so it can’t get a new link or a response. When it happens The quote’s expires_at has passed, and you called either:
  • POST /v1/quotes/{id}/hosted-link. Quotes expire 30 days after they’re created, and a new link never extends that.
  • POST /v1/test_helpers/quotes/{id}/interest, on a test quote. An expired quote takes no response, just as its interactive quote doesn’t.
What to do Create a new quote with the same details, and send your client its hosted_url (or, in test mode, act out the response on the new quote).

QUOTE_ALREADY_INTERESTED

409 Conflict · type conflict · Open page The test quote already has your client’s response. A quote takes one response only. When it happens You called POST /v1/test_helpers/quotes/{id}/interest on a test quote whose status is already interested, whether from an earlier call or from someone tapping I’m interested on its interactive quote. Like the interactive quote itself, a quote takes one response only. What to do Read the response that’s already recorded with GET /v1/quotes/{id}. To act it out again, create a new test quote.

IDEMPOTENCY_KEY_REUSED

409 Conflict · type conflict · Open page This Idempotency-Key was already used for a different request. When it happens Within the last 24 hours, the same key was sent with a different request: another path, another body, or another acting broker. Bodies are compared byte for byte, so re-serializing the same data can count as different (keys reordered, spacing changed). What to do Use a new key for a new request. To retry, resend the exact bytes you sent the first time. See idempotency.

IDEMPOTENCY_REQUEST_IN_PROGRESS

409 Conflict · type conflict · Open page The first request with this Idempotency-Key is still running. When it happens You retried while the original request with the same key was still being processed, usually because the first attempt timed out on your side. What to do Wait for the Retry-After header (1 second) and retry with the same key. You’ll get the original response once it finishes.

429 and 5xx

RATE_LIMITED

429 Too Many Requests · type rate_limit · Open page Too many requests: you’re over a per-minute or daily limit. When it happens The key went over 60 requests a minute, or POST /v1/quotes went over 500 quotes a day for the key or 2,000 a day for your agency. Every authenticated request counts, including ones that fail validation. What to do Wait the number of seconds in Retry-After, then retry with the same Idempotency-Key. For a daily limit, that’s until midnight UTC. See rate limits.

INTERNAL

500 Internal Server Error · type api_error · Open page Something went wrong on our side. When it happens An unexpected error. We log every one with its request id. What to do Retry with the same Idempotency-Key, with backoff. Usually nothing was stored and the retry runs normally. If a retry returns this same 500 with the header Idempotent-Replayed: true, that’s the stored outcome of a request that may have taken effect: stop retrying that key, and handle it like IDEMPOTENCY_RECORD_LOST. If it keeps happening, contact us with the request_id.

IDEMPOTENCY_RECORD_LOST

500 Internal Server Error · type api_error · Open page The original request with this key may have finished, but its response was lost. This key will never succeed. When it happens You retried with an Idempotency-Key whose original request started more than two minutes ago and never recorded a response, for example because the server stopped after doing the work but before saving the answer. We can’t replay a response we don’t have, and we won’t run the request again in case it already took effect. What to do Don’t retry with this key; it will keep failing. There’s no Retry-After.
  • POST /v1/quotes: create the quote again with a new key. A duplicate quote is harmless: nothing is sent to anyone, and it expires on its own.
  • POST /v1/quotes/{id}/hosted-link: call it again with a new key. That revokes whichever link is current and returns a fresh one.
See idempotency.

SERVICE_UNAVAILABLE

503 Service Unavailable · type api_error · Open page We can’t price right now. Nothing was stored; retry shortly. When it happens POST /v1/quotes couldn’t read something it needs to price safely, such as current market rates or pricing settings. We refuse to quote rather than guess. What to do Wait the number of seconds in Retry-After (30), then retry with the same Idempotency-Key. Nothing was stored, so the retry runs normally.