# Offers

Once an application clears underwriting, Quantum returns one or more **offers**. Each offer represents a financing product the applicant is approved for. This guide explains how to retrieve offers and — importantly — which fields to expect for each product type.

{% callout type="info" %}
**Why offers look different from one another.** The offers endpoint returns a list of offers, but not every offer has the same shape. A Fee Based Line of Credit offer carries different fields than a Revenue Based Advance. The field you read depends on the offer's `loan_type`. This guide maps out exactly which fields appear for each product type.
{% /callout %}

## Retrieving offers

{% endpoint method="GET" path="/api/v3/applications/{app_id}/offers" /%}

Returns every offer generated for the application.

{% parameter name="app_id" type="string (uuid)" required=true /%}

The response is an `Offers` object: the application ID plus an array of offer objects.

```json
{
  "application_id": "550e8400-e29b-41d4-a716-446655440001",
  "offers": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "loan_type": "fee_based_loc",
      "payment_frequency": "monthly",
      "term": 36,
      "has_disclosure": true,
      "expires_at": "2025-10-31 11:23:10",
      "status": "presented",
      "decline_reason": null,
      "annual_fee_in_cents": 10000,
      "commitment_fee_amount_in_cents": 10000,
      "facility_size_in_cents": 12500000,
      "minimum_draw_amount_in_cents": 100000,
      "basis_fee": "200.00"
    },
    {
      "id": "660e8400-e29b-41d4-a716-446655440022",
      "loan_type": "revenue_based_advance",
      "payment_frequency": "monthly",
      "term": 12,
      "has_disclosure": true,
      "expires_at": "2025-10-31 11:23:10",
      "status": "presented",
      "decline_reason": null,
      "amount_in_cents": 10000000,
      "amortized_payment_amount_in_cents": 549189,
      "factor_rate": "1.10",
      "revenue_share_amount_in_cents": 0
    }
  ]
}
```

Notice the two offers above carry **different fields**. The first has `basis_fee` and `facility_size_in_cents`; the second has `factor_rate` and `amount_in_cents`. The next section explains why.

## The four product types

In the OpenAPI spec, each item in the `offers` array is an `anyOf` across four schemas. In practice this is a **discriminated union** — the `loan_type` field tells you which product type an offer is, and therefore which fields it will contain.

| Product type | `loan_type` value | Schema |
|---|---|---|
| Fee Based Line of Credit | `fee_based_loc` | `FeeBasedLOCOffer` |
| Term Line of Credit | `term_loc` | `TermLOCOffer` |
| Term Loan | `standard_term_loan` | `TermLoanOffer` |
| Revenue Based Advance | `revenue_based_advance` | `RevenueBasedAdvanceOffer` |

{% callout type="success" %}
**Integration tip.** Always branch on `loan_type` first, then read the product-specific fields. Do not assume a field is present just because it appeared on another offer in the same response.
{% /callout %}

## Fields present on every offer

These fields belong to **all** product types, so you can read them without checking `loan_type`. The first seven are always present; `decline_reason` is optional (see the note below).

| Field | Type | Required | Description |
|---|---|:---:|---|
| `id` | string (uuid) | Yes | Offer ID. Use this to accept the offer or fetch its disclosure. |
| `loan_type` | enum | Yes | The product type: `fee_based_loc`, `term_loc`, `standard_term_loan`, or `revenue_based_advance`. |
| `payment_frequency` | enum | Yes | `monthly` or `semi_monthly`. |
| `term` | integer | Yes | Term in months (e.g. `12`, `24`, `36`, `48`, `60`). |
| `has_disclosure` | boolean | Yes | Whether a commercial financing disclosure PDF is available (true for states such as CA and NY). |
| `expires_at` | string | Yes | When the offer expires (e.g. `2025-10-31 11:23:10`). |
| `status` | enum | Yes | `presented`, `accepted`, or `rejected`. |
| `decline_reason` | string \| null | No | Reason the offer was declined, if applicable. Optional and nullable — the key may be `null` or omitted entirely, so don't dereference it unconditionally. |

## Which extra fields each product type carries

Beyond the shared fields, each product type adds its own. `✓` = part of that product type's schema; `○` = part of the schema but **optional/nullable** (the key may be `null` or omitted); `—` = not part of that product type's schema.

| Field | Fee Based LOC | Term LOC | Term Loan | Revenue Based Advance |
|---|:---:|:---:|:---:|:---:|
| `annual_fee_in_cents` | ✓ | ✓ | — | — |
| `commitment_fee_amount_in_cents` | ○ | ○ | — | — |
| `facility_size_in_cents` | ✓ | ✓ | — | — |
| `minimum_draw_amount_in_cents` | ○ | ○ | — | — |
| `basis_fee` | ✓ | — | — | — |
| `interest_rate` | — | ✓ | ✓ | — |
| `draw_fee` | — | ✓ | — | — |
| `amount_in_cents` | — | — | ✓ | ✓ |
| `amortized_payment_amount_in_cents` | — | — | ✓ | ✓ |
| `revenue_share_amount_in_cents` | — | — | ✓ | ✓ |
| `origination_and_closing_fees` | — | — | ✓ | — |
| `factor_rate` | — | — | — | ✓ |

### Fee Based Line of Credit (`fee_based_loc`)

A revolving line of credit priced with fees rather than interest. Adds:

- `annual_fee_in_cents`
- `commitment_fee_amount_in_cents` *(optional/nullable)*
- `facility_size_in_cents`
- `minimum_draw_amount_in_cents` *(optional/nullable)*
- `basis_fee`

### Term Line of Credit (`term_loc`)

A revolving line of credit priced with an interest rate and per-draw fee. Adds:

- `annual_fee_in_cents`
- `commitment_fee_amount_in_cents` *(optional/nullable)*
- `facility_size_in_cents`
- `minimum_draw_amount_in_cents` *(optional/nullable)*
- `interest_rate`
- `draw_fee`

### Term Loan (`standard_term_loan`)

A fixed-amount installment loan with an interest rate. Adds:

- `amount_in_cents`
- `amortized_payment_amount_in_cents`
- `interest_rate`
- `revenue_share_amount_in_cents`
- `origination_and_closing_fees`

### Revenue Based Advance (`revenue_based_advance`)

A lump-sum advance repaid via a factor rate rather than interest. Adds:

- `amount_in_cents`
- `amortized_payment_amount_in_cents`
- `factor_rate`
- `revenue_share_amount_in_cents`

## Field reference

| Field | Type | Description |
|---|---|---|
| `annual_fee_in_cents` | integer | Annual fee, in cents. |
| `commitment_fee_amount_in_cents` | integer \| null | Commitment fee, in cents. Optional/nullable — may be `null` or omitted. |
| `facility_size_in_cents` | integer | Facility size (credit limit), in cents. |
| `minimum_draw_amount_in_cents` | integer \| null | Minimum draw amount, in cents. Optional/nullable — may be `null` or omitted. |
| `basis_fee` | number \| string | Basis fee amount, a decimal that may arrive as a JSON number (`200.00`) or string (`"200.00"`). |
| `interest_rate` | number \| string | Interest rate as a fraction, decimal as number (`0.05`) or string (`"0.05"` = 5%). |
| `draw_fee` | number \| string | Fee charged per draw, decimal as number (`15.00`) or string (`"15.00"`). |
| `amount_in_cents` | integer | Principal loan / advance amount, in cents. |
| `amortized_payment_amount_in_cents` | integer | Amortized payment amount, in cents. |
| `revenue_share_amount_in_cents` | integer | Revenue share amount, in cents. |
| `factor_rate` | number \| string | Factor rate applied to the advance, decimal as number (`1.10`) or string (`"1.10"`). |
| `origination_and_closing_fees` | number \| string | Total origination & closing fee for a Term Loan, expressed as a **whole-number percent of the loan amount** — `5.00` means 5% (note: **not** a fraction like `interest_rate`, and **not** a dollar amount). A decimal that may arrive as a JSON number (`5.00`) or string (`"5.00"`). Term Loan offers only. |

{% callout type="warning" %}
**Money and number formats.** Every field ending in `_in_cents` is an **integer number of cents** — divide by 100 for the dollar amount (`12500000` → $125,000.00). The rate and fee fields — `basis_fee`, `interest_rate`, `draw_fee`, `factor_rate`, and `origination_and_closing_fees` — are decimals the API may return **either as a JSON number (`5.00`) or as a string (`"5.00"`)**; handle both, and parse them as decimals (not floats) to preserve precision. Watch the units, which differ by field: `basis_fee` and `draw_fee` are plain **dollar amounts** (`"15.00"` = $15.00); `interest_rate` is a **fraction** (`"0.05"` = 5%); `origination_and_closing_fees` is a **whole-number percent** of the loan amount (`"5.00"` = 5%); and `factor_rate` is a unitless multiplier (`"1.10"`).
{% /callout %}

## Working with offers

Once you have the offers, you can act on them:

- **Accept an offer** — `POST /api/v3/applications/{app_id}/offer/{offer_id}/accept`. On success the offer's `status` becomes `accepted`.
- **Decline offers** — `POST /api/v3/applications/{app_id}/decline-offers`.
- **Download the disclosure PDF** — when `has_disclosure` is `true`, `GET /api/v3/applications/{app_id}/offers/{offer_id}/disclosure` returns the commercial financing disclosure document.

See the [API Reference](/api-reference.html) for full request and response schemas for each of these endpoints.

{% callout type="info" %}
**Offers emit webhook events.** Rather than polling, you can react to offer activity in real time by subscribing to these events:

- `application.offer.created` — a loan offer has been generated for the applicant
- `application.offer.selected` — the customer selected/accepted an offer
- `application.offer.declined` — the customer declined an offer

See the [Webhooks Overview](/webhooks-overview.html) and [Webhooks Integration Guide](/webhooks-guide.html) to subscribe.
{% /callout %}

## Required disclosure step for New York & California

{% callout type="warning" %}
**New York and California have a regulatory requirement you must implement.** For a business located in **NY** or **CA**, you **must download and display the offer's commercial financing disclosure before you accept the offer**. Acceptance is blocked until the disclosure has been downloaded for that offer.
{% /callout %}

This requirement exists so that, for NY/CA borrowers, Quantum can demonstrate the disclosure was presented to the applicant before they committed to the offer. Downloading the disclosure records the presentation; accepting then records the acknowledgement.

The `has_disclosure` flag on each offer tells you when a disclosure exists. It is `true` for NY/CA offers — and for those offers the disclosure must be downloaded before the offer can be accepted. When it is `false`, the offer has no disclosure and calling the disclosure endpoint would return `404`.

**You are responsible for implementing this flow in your integration.** The correct sequence is:

1. Retrieve offers — `GET /api/v3/applications/{app_id}/offers`
2. If `offer.has_disclosure` is `true`, **download and present the disclosure** — `GET /api/v3/applications/{app_id}/offers/{offer_id}/disclosure`. This is required before acceptance for NY/CA offers.
3. Accept the offer — `POST /api/v3/applications/{app_id}/offer/{offer_id}/accept`

```javascript
const base = `https://api.quantum.com/api/v3/applications/${appId}`;
const headers = { 'Authorization': 'Bearer YOUR_API_TOKEN' };

// 1. Retrieve offers and pick one.
const { offers } = await (await fetch(`${base}/offers`, { headers })).json();
const offer = offers[0];

// 2. If the offer has a disclosure (true for NY/CA), download and display it
//    first. This records that it was presented to the applicant, and is
//    required before the offer can be accepted.
if (offer.has_disclosure) {
  const disclosure = await fetch(`${base}/offers/${offer.id}/disclosure`, { headers });
  const disclosurePdf = await disclosure.blob(); // present and retain the PDF
}

// 3. Accept the offer.
const accept = await fetch(`${base}/offer/${offer.id}/accept`, {
  method: 'POST',
  headers,
});

if (accept.status === 412) {
  // NY/CA: the disclosure has not been downloaded for this offer yet.
  // Call the disclosure endpoint above, then retry the accept.
}
```

If you attempt to accept a NY/CA offer **before** downloading its disclosure, the API responds with **`412 Precondition Failed`**:

```json
{
  "error": {
    "code": "PRECONDITION_FAILED",
    "message": "Download the offer disclosure before accepting this offer."
  }
}
```

Branch on the **`412` status code** to detect this case. To resolve it, download the disclosure for that offer and then retry the acceptance.

{% callout type="info" %}
The download-before-accept requirement applies **only to businesses located in New York or California**. For all other states, accept the offer directly — no disclosure download is required. Only call the disclosure endpoint when the offer's `has_disclosure` flag is `true`.
{% /callout %}
