> ## 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.

# Send your client the interactive quote

> Every quote comes with a page your client can open, compare options on and say yes from. Here's how it works and how their answer reaches you.

Every quote you create comes with a `hosted_url`: a page made for your client, usually opened on a phone. It shows every option you can offer on one grid, and lets them choose one and tell your broker in one tap.

You don't have to build a comparison screen, explain APR or chase a reply. You send a link; your broker hears back.

## What your client sees

* **Your agency first.** Your agency's name and brand color lead the page, with "Prepared by" and the broker's name, and a quiet "Financing by Bridgeline Premium Finance" credit. The broker's email and phone are never shown.
* **The whole grid, priced.** Every down payment and term, with the monthly payment in each cell. The recommended option is selected when the page opens, and the lowest monthly payment and lowest total cost are marked.
* **The numbers for their choice.** Monthly payment, down payment, APR, amount financed and total cost, in plain language, with a short "What this means" explainer.
* **One action.** **I'm interested**, with an optional note to the broker (up to 500 characters), such as the best time to call.
* **The terms of the offer.** A footer says the quote is indicative, when it was priced and when it expires.

It never shows anything internal or sensitive: no FEIN, address, policy numbers or pricing internals. The page is excluded from search engines and sends no referrer when your client follows a link off it.

## Send the link

`hosted_url` is in the `201` response to `POST /v1/quotes`, and only there. Store it with the quote.

```json theme={null}
{
  "id": "qte_2lo4LFk5rf8toDFJHSUZ2O",
  "hosted_url": "https://portal.bridgelinepf.com/q/p98_xZUO2zaltiX49vC59BgOE1EUoRZSpIGtWjFUs0M",
  "expires_at": "2026-11-03T15:04:05Z"
}
```

Deliver it however you reach the client: your email template, a text, a button in your client portal. **We never send it for you**, so nothing goes to your client until you decide.

Treat the link like a key. Anyone who has it can see the options and respond, and it can't be guessed. If it went to the wrong person, [replace it](#replace-a-link).

## When your client says yes

When your client taps **I'm interested**:

1. The quote's `status` becomes `interested` and `selected_option_id` is set to the option they chose. **The choice is final**: the page shows "Sent to" your broker, and to change it the client replies to the broker directly.
2. We email the quote's broker with the choice and the note, usually within a minute. If that broker is no longer active, we email your agency's admins instead.
3. `GET /v1/quotes/{id}` shows everything in `interest`.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://portal.bridgelinepf.com/api/v1/quotes/qte_2lo4LFk5rf8toDFJHSUZ2O \
    -H "Authorization: Bearer $BRIDGELINE_API_KEY"
  ```

  ```javascript Node theme={null}
  const res = await fetch(`https://portal.bridgelinepf.com/api/v1/quotes/${quoteId}`, {
    headers: {
      Authorization: `Bearer ${process.env.BRIDGELINE_API_KEY}`,
    },
  })
  const quote = await res.json()
  if (quote.status === 'interested') {
    console.log(quote.interest.option_id, quote.interest.note)
  }
  ```

  ```python Python theme={null}
  import os
  import requests

  res = requests.get(
      f"https://portal.bridgelinepf.com/api/v1/quotes/{quote_id}",
      headers={
          "Authorization": f"Bearer {os.environ['BRIDGELINE_API_KEY']}",
      },
      timeout=30,
  )
  quote = res.json()
  if quote["status"] == "interested":
      print(quote["interest"]["option_id"], quote["interest"]["note"])
  ```
</CodeGroup>

```jsonc 200 OK (abridged) theme={null}
{
  "id": "qte_2lo4LFk5rf8toDFJaD9Xoe",
  "object": "quote",
  "status": "interested",
  "hosted_url": null,
  "selected_option_id": "opt_20_9",
  "interest": {
    "option_id": "opt_20_9",
    "note": "Can we start the first payment in November?",
    "submitted_at": "2026-10-05T15:02:11Z",
    "broker_notification": {
      "status": "sent",
      "reason": null,
      "recipient": "broker",
      "recipients": ["maria@lonestarrisk.example"],
      "at": "2026-10-05T15:02:13Z"
    }
  }
  // ...the rest of the quote, unchanged since it was created
}
```

<Warning>
  `interest.note` is text your client typed on a public page. Escape it before you render it anywhere.
</Warning>

### Did the broker get the email?

`interest.broker_notification` records what happened to the email:

| `status` | `reason` | What it means |
| - | - | - |
| `pending` | `null` | The choice is recorded and the email is on its way |
| `sent` | `null` | We emailed `recipients` |
| `skipped` | `demo_agency` | A demo agency: we email only internal Bridgeline addresses, and none applied |
| `skipped` | `test_mode` | A test-mode quote, which never emails anyone |
| `skipped` | `no_recipient` | Your agency had no active broker or admin to email |
| `skipped` | `email_disabled` | Email is switched off in this environment |
| `failed` | `send_failed` | The email couldn't be sent. Bridgeline is alerted; follow up with your client yourself |

`recipient` is `broker` or `agency_admins`. With a broker key, `recipients` is empty when the email went to the admins, because a broker key can't see their addresses.

### Checking for a response

Webhooks are [on the roadmap](/roadmap). Until then, poll `GET /v1/quotes/{id}`:

* Poll only quotes you've actually sent, every few minutes at most. The per-key limit is 60 requests a minute across every endpoint.
* Stop when `status` is `interested` or `expired`.
* Treat a `status` you don't recognize as "not usable". More statuses will be added.

Whatever your integration does, your broker still gets the email for a live quote.

To test this code without opening the link yourself, create a quote with a test key and call [`POST /v1/test_helpers/quotes/{id}/interest`](/api-reference/test-helpers/quote-interest). The quote then reads back as if your client had responded.

## Replace a link

`POST /v1/quotes/{id}/hosted-link` revokes the current link and returns a new one. Use it when a link went to the wrong person, or when you need the link again (`GET` always returns `hosted_url: null`). There's no request body.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://portal.bridgelinepf.com/api/v1/quotes/qte_2lo4LFk5rf8toDFJHSUZ2O/hosted-link \
    -H "Authorization: Bearer $BRIDGELINE_API_KEY" \
    -H "Idempotency-Key: $(uuidgen)"
  ```

  ```javascript Node theme={null}
  const res = await fetch(`https://portal.bridgelinepf.com/api/v1/quotes/${quoteId}/hosted-link`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.BRIDGELINE_API_KEY}`,
      'Idempotency-Key': crypto.randomUUID(),
    },
  })
  const { hosted_url } = await res.json()
  ```

  ```python Python theme={null}
  import os
  import uuid
  import requests

  res = requests.post(
      f"https://portal.bridgelinepf.com/api/v1/quotes/{quote_id}/hosted-link",
      headers={
          "Authorization": f"Bearer {os.environ['BRIDGELINE_API_KEY']}",
          "Idempotency-Key": str(uuid.uuid4()),
      },
      timeout=30,
  )
  hosted_url = res.json()["hosted_url"]
  ```
</CodeGroup>

```json 200 OK theme={null}
{
  "id": "qte_2lo4LFk5rf8toDFJHSUZ2O",
  "hosted_url": "https://portal.bridgelinepf.com/q/4nHnCzyp1YZ78mOscafTROmG9hSYlXaplWVeA8CeU90",
  "expires_at": "2026-11-03T15:04:05Z"
}
```

* **The old link stops working at once,** for everyone. It now opens a neutral "This link isn't active" page that names no agency.
* **Expiry never moves.** The new link expires with the quote. To give your client more time, create a new quote.
* **An expired quote can't get a new link:** [`409 QUOTE_EXPIRED`](/errors/QUOTE_EXPIRED).
* **An interested quote can.** The new link shows your client's choice, not the options again.
* **Retries are safe.** The same `Idempotency-Key` returns the same link without revoking it again. A new key, or no key, mints another link and revokes the last one.
* A broker key can replace links only for its own broker's quotes. Anything else is `404`, as with `GET`.

## Links outlive API access

A link belongs to your client once you've sent it. Turning off your agency's API access, or revoking the key that created the quote, stops new API calls only. Links already sent keep working until the quote expires, and your client can still say yes.

To stop one link, [replace it](#replace-a-link). To stop all of a quote's links, replace its link and don't send the new one.

## What the page shows, by state

| Quote | Your client sees |
| - | - |
| `active` | The grid and **I'm interested** |
| `interested` | "Sent to" the broker, with their choice |
| `expired` | The grid dimmed, marked expired, and a prompt to ask you for an updated quote |
| Ineligible, or no options | No grid: "Your agent will follow up", with no internal reasons |
| Replaced or mistyped link | "This link isn't active", naming no agency |
| From a demo agency | Labeled "Example quote" |
| Created with a test key | Labeled "Test mode": not a real offer, and choosing an option notifies no one |


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