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.statethat isn’t a two-letter USPS state code (detail codeINVALID_FORMAT). A full state name getsUse the two-letter state code, e.g. "TX" for Texas.; anything else getsMust 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 a201ineligible quote;minimum_earnedwith both or neither ofrateandamount;- a coverage
typethat isn’t on the list, or a misspelled field name; - a blank
broker_email; - more than 25 policies (one
TOO_MANYdetail, before anything else is checked).
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
Authorizationheader, or it doesn’t start withBearer. - 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.
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.
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.
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.
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.