> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bridgelinepf.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling errors

> One error shape across the API, stable codes to branch on, and every problem in a request reported at once.

Every error uses an HTTP status and the same JSON body:

```json 422 Unprocessable Entity theme={null}
{
  "error": {
    "type": "invalid_request",
    "code": "VALIDATION_FAILED",
    "message": "Invalid request body: policies[0].premium: Send money as a decimal string, e.g. \"46100.00\", not a JSON number. (and 3 more; see details)",
    "param": "policies[0].premium",
    "details": [
      {
        "code": "INVALID_TYPE",
        "param": "policies[0].premium",
        "message": "Send money as a decimal string, e.g. \"46100.00\", not a JSON number."
      },
      {
        "code": "INVALID_MINIMUM_EARNED",
        "param": "policies[0].minimum_earned",
        "message": "minimum_earned must have exactly one of rate (a fraction, e.g. 0.25) or amount (e.g. \"11525.00\")."
      },
      {
        "code": "UNKNOWN_FIELD",
        "param": "policies[0].polcy_number",
        "message": "\"polcy_number\" is not a field here. Did you mean \"policy_number\"?"
      },
      {
        "code": "UNKNOWN_VALUE",
        "param": "policies[0].coverages[0].type",
        "message": "\"general liability\" is not a coverage type. Did you mean \"general_liability\"?"
      }
    ],
    "doc_url": "https://docs.bridgelinepf.com/errors#VALIDATION_FAILED",
    "request_id": "req_8fJ2kQ9xLm4TzW7nB3cY5pDv"
  }
}
```

| Field | What it is |
| - | - |
| `type` | The broad category, one of seven (below) |
| `code` | The specific error. **Branch on this.** Codes are a stable contract: we add new ones and never rename or repurpose one |
| `message` | A sentence for a developer to read. It can change at any time, so never parse it |
| `param` | The request field or header at fault, when there is one, in request notation (`policies[0].premium`) |
| `details` | Every individual problem, when there's more than one thing to say. Present on `VALIDATION_FAILED` |
| `doc_url` | The [error code page](/errors) for `code` |
| `request_id` | Our id for this request. Include it when you contact us |

The `Request-Id` response header carries the same id on every response, successful or not. Log it.

## Types and statuses

| Status | `type` | Codes | What to do |
| - | - | - | - |
| 400, 405, 422 | `invalid_request` | [`VALIDATION_FAILED`](/errors/VALIDATION_FAILED), [`INVALID_JSON`](/errors/INVALID_JSON), [`INVALID_REQUEST`](/errors/INVALID_REQUEST), [and more](/errors#400-and-422-the-request) | Fix the request. Don't retry it unchanged |
| 401 | `authentication` | [`INVALID_API_KEY`](/errors/INVALID_API_KEY), [`KEY_REVOKED`](/errors/KEY_REVOKED), [`KEY_EXPIRED`](/errors/KEY_EXPIRED) | Check or replace the key |
| 403 | `permission` | [`API_ACCESS_NOT_ENABLED`](/errors/API_ACCESS_NOT_ENABLED), [`TEST_MODE_NOT_ENABLED`](/errors/TEST_MODE_NOT_ENABLED), [`MISSING_SCOPE`](/errors/MISSING_SCOPE), [`BROKER_NOT_ACTIVE`](/errors/BROKER_NOT_ACTIVE), [and more](/errors#403-permission) | Change the key's scopes or the acting broker, or ask Bridgeline to enable access |
| 404 | `not_found` | [`NOT_FOUND`](/errors/NOT_FOUND) | Check the id, and that the key can see it |
| 409 | `conflict` | [`QUOTE_EXPIRED`](/errors/QUOTE_EXPIRED), [`QUOTE_ALREADY_INTERESTED`](/errors/QUOTE_ALREADY_INTERESTED), [`IDEMPOTENCY_KEY_REUSED`](/errors/IDEMPOTENCY_KEY_REUSED), [`IDEMPOTENCY_REQUEST_IN_PROGRESS`](/errors/IDEMPOTENCY_REQUEST_IN_PROGRESS) | Depends on the code |
| 429 | `rate_limit` | [`RATE_LIMITED`](/errors/RATE_LIMITED) | Wait for `Retry-After` |
| 500, 503 | `api_error` | [`INTERNAL`](/errors/INTERNAL), [`SERVICE_UNAVAILABLE`](/errors/SERVICE_UNAVAILABLE), [`IDEMPOTENCY_RECORD_LOST`](/errors/IDEMPOTENCY_RECORD_LOST) | Retry, following the [retry rules](/guides/idempotency#retry-rules) |

New types and codes can appear. Handle an unknown `code` by its `type` and HTTP status.

## Every problem at once

`POST /v1/quotes` checks the whole body and reports every problem in one `422`, so you can fix them all before trying again. Each entry in `details` has its own `code`, a `param` pointing at the field, and a `message` you can show a user next to that field. `param` and `message` are the stable parts; detail codes such as `REQUIRED`, `INVALID_TYPE`, `INVALID_FORMAT`, `UNKNOWN_FIELD`, `UNKNOWN_VALUE` and `OUT_OF_RANGE` help you group them, and new ones can be added.

Unknown fields are always rejected, with a "did you mean" when one is close. That catches a misspelled field before it silently does nothing.

The insured's state is a common one. `insured.address.state` must be a two-letter USPS state code (the 50 states, `DC`, `PR`, `GU`, `VI`, `AS` or `MP`). Anything else is an `INVALID_FORMAT` detail: a full state name gets `Use the two-letter state code, e.g. "TX" for Texas.`, and any other value gets `Must be a two-letter US state code, e.g. "TX".`

## Not an error: an ineligible deal

A deal we can't finance is a successful `201` quote with `eligibility.status: "ineligible"`, its reasons and no options. A `422` means only that the request itself was malformed. For example, a valid state code outside Texas, such as `OK`, gets a `201` ineligible quote, while `Oklahoma` gets a `422`. See [eligibility](/concepts/eligibility).

## Ids you can't see are `404`

A malformed id, a quote from another agency, a quote in the other mode, and a colleague's quote read with a broker key all return the same [`404 NOT_FOUND`](/errors/NOT_FOUND). An id never reveals whether a deal exists outside what your key can see.

## Handling errors in code

<CodeGroup>
  ```javascript Node theme={null}
  const res = await fetch('https://portal.bridgelinepf.com/api/v1/quotes', { /* ... */ })

  if (!res.ok) {
    const { error } = await res.json()
    switch (error.code) {
      case 'VALIDATION_FAILED':
        for (const d of error.details ?? []) showFieldError(d.param, d.message)
        break
      case 'BROKER_NOT_ACTIVE':
        // The logged-in user isn't an active broker at the agency in Bridgeline.
        break
      default:
        console.error(`Bridgeline ${res.status} ${error.code} (${error.request_id}): ${error.message}`)
    }
  }
  ```

  ```python Python theme={null}
  res = requests.post("https://portal.bridgelinepf.com/api/v1/quotes", ...)

  if not res.ok:
      error = res.json()["error"]
      if error["code"] == "VALIDATION_FAILED":
          for d in error.get("details", []):
              show_field_error(d.get("param"), d["message"])
      elif error["code"] == "BROKER_NOT_ACTIVE":
          pass  # The logged-in user isn't an active broker at the agency in Bridgeline.
      else:
          log.error("Bridgeline %s %s (%s): %s", res.status_code, error["code"], error["request_id"], error["message"])
  ```
</CodeGroup>

For the full list, with what causes each code and what to do, see [error codes](/errors).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.