# API: Quotes

| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | `/v1/cpq/billing` | Billing systems for signed quotes (NetSuite, Metronome, Stripe): connected, on, status and settings; never credentials (owners) | `integrations:write` |
| POST | `/v1/cpq/billing-pushes/:id/cancel` | Withdraw a billing write still waiting for approval (whoever asked, or an owner) | `deals:write` |
| POST | `/v1/cpq/billing-pushes/:id/fail` | Fail a billing write stuck running for over 15 minutes; what it had started is marked unknown for a person to check (owners) | `deals:write` |
| POST | `/v1/cpq/billing-pushes/:id/refresh` | Read a written quote's billing state now (orders, invoices, payments, subscription or contract); read only | `deals:write` |
| DELETE | `/v1/cpq/billing/:vendor` | Remove a billing system's credentials and turn it off (owners) | `integrations:write` |
| PUT | `/v1/cpq/billing/:vendor` | Connect a billing system with your own account (NetSuite token-based authentication, a Metronome token; Stripe uses your Stripe connection), its mappings, and turn it on or off (owners) | `integrations:write` |
| POST | `/v1/cpq/billing/:vendor/check` | Check a billing system's saved credentials with one read (owners) | `integrations:write` |
| GET | `/v1/cpq/catalog` | Products and their current prices | `deals:read` |
| POST | `/v1/cpq/catalog/import/document` | Read products and prices from an order form, contract, CRM export or call as a plan with quotes from the source (owners) | `settings:write` |
| POST | `/v1/cpq/catalog/import/sheet` | Read a price sheet (.xlsx or .csv) as a plan, each value traced to its row and cell; accept entries to apply them (owners) | `settings:write` |
| POST | `/v1/cpq/catalog/import/stripe` | Read products and prices from your Stripe account (read-only) as a plan; accept entries to apply them (owners) | `settings:write` |
| POST | `/v1/cpq/contract-periods/:id/close` | Close a period: overage past the credits, and the unused share rolled into the next (owners) | `settings:write` |
| GET | `/v1/cpq/contracts` | Contracts from signed quotes | `deals:read` |
| GET | `/v1/cpq/contracts/:id` | A contract with its periods: committed, credits granted, rolled in, used, overage and rolled out | `deals:read` |
| POST | `/v1/cpq/contracts/:id/usage` | Record usage against a contract line (an integration, or a person) | `deals:write` |
| GET | `/v1/cpq/documents/:id` | Download a stored document; its SHA-256 is checked before it's returned | `deals:read` |
| GET | `/v1/cpq/drafts` | Your open drafts | `deals:read` |
| GET | `/v1/cpq/drafts/:id` | A draft with its source quotes, confidence and preview | `deals:read` |
| POST | `/v1/cpq/drafts/:id/accept` | Accept a draft you reviewed: a request or structure becomes a draft quote, a change is applied, rules or catalog entries are saved | `deals:write` |
| POST | `/v1/cpq/drafts/:id/discard` | Discard a draft | `deals:write` |
| POST | `/v1/cpq/drafts/from-request` | Read a request for quote (pasted text, a file, an email or call) or a deal description into catalog line items, priced by the engine; held lines wait for you | `deals:write` |
| POST | `/v1/cpq/drafts/structure` | Propose a deal structure (commit, ramp, expected usage) from the deal's calls and comparable won quotes | `deals:write` |
| DELETE | `/v1/cpq/esign` | Disconnect Documenso (owners) | `integrations:write` |
| GET | `/v1/cpq/esign` | Whether Documenso is connected (owners) | `integrations:write` |
| PUT | `/v1/cpq/esign` | Connect Documenso (cloud or self-hosted): API URL, token and webhook secret, stored encrypted (owners) | `integrations:write` |
| GET | `/v1/cpq/intel` | Pricing intelligence: win rate by discount band, margin trend, competitors named on the deal and how deals against them ended | `deals:read` |
| DELETE | `/v1/cpq/links/:id` | Revoke a tracked link | `deals:write` |
| GET | `/v1/cpq/pipeline` | Open quotes: count, value, age, expiry, buyer activity and follow-up state, with who to chase next and why | `deals:read` |
| PATCH | `/v1/cpq/prices/:id` | Offer or withdraw a price (owners) | `settings:write` |
| POST | `/v1/cpq/prices/:id/versions` | Change a price: saves its next version (the old one stays, for the quotes priced with it) (owners) | `settings:write` |
| POST | `/v1/cpq/products` | Add a product (owners) | `settings:write` |
| PATCH | `/v1/cpq/products/:id` | Change a product (owners) | `settings:write` |
| POST | `/v1/cpq/products/:id/prices` | Add a price to a product (owners) | `settings:write` |
| GET | `/v1/cpq/quotes` | Quotes, newest change first | `deals:read` |
| POST | `/v1/cpq/quotes` | Create a quote on a deal; it's priced at once and every number carries its evidence | `deals:write` |
| GET | `/v1/cpq/quotes/:id` | A quote: lines, every number with its evidence and formula, rules that apply, approvals and versions | `deals:read` |
| PATCH | `/v1/cpq/quotes/:id` | Change a quote (send the version you saw); a change to its prices makes earlier approvals stale | `deals:write` |
| POST | `/v1/cpq/quotes/:id/approval` | Ask for the approvals this quote needs (the rules decide who; with none needed it's approved at once) | `deals:write` |
| GET | `/v1/cpq/quotes/:id/approver-context` | What an approver sees: rules that fired, totals, versions, earlier decisions, and this buyer's past quotes | `deals:read` |
| GET | `/v1/cpq/quotes/:id/billing` | The quote's billing writes: each request, its approval, what was written and read back, and the billing state read since | `deals:read` |
| POST | `/v1/cpq/quotes/:id/billing` | Ask for a signed quote to be written to a billing system: an owner approves the exact plan in the inbox before anything is written | `deals:write` |
| GET | `/v1/cpq/quotes/:id/billing/plan` | What a signed quote writes to one billing system, line by line, and anything that stops it (the stored plan while a request is open) | `deals:read` |
| POST | `/v1/cpq/quotes/:id/change-request` | A change in plain language ("annual, start Oct 15, 15% off seats") as operations, re-priced with today's rules, for you to apply | `deals:write` |
| POST | `/v1/cpq/quotes/:id/crm-attachment` | Attach the signed order form PDF to the deal in each connected CRM (HubSpot, Salesforce), through policy, once each | `deals:write` |
| POST | `/v1/cpq/quotes/:id/derive` | A renewal, amendment, expansion or cancellation quote from a signed one (renewals from live usage; amendments co-terminate) | `deals:write` |
| GET | `/v1/cpq/quotes/:id/documents` | The quote's stored documents (order forms and signed copies) with their hashes | `deals:read` |
| POST | `/v1/cpq/quotes/:id/documents` | Render the quote's order form as a PDF (stored with its SHA-256; what's signed), a .docx, or a slide outline | `deals:write` |
| GET | `/v1/cpq/quotes/:id/followups` | The quote's follow-up cadence: each step, when it's due, and what happened | `deals:read` |
| POST | `/v1/cpq/quotes/:id/followups/stop` | Stop the quote's follow-ups | `deals:write` |
| GET | `/v1/cpq/quotes/:id/links` | The quote's tracked links | `deals:read` |
| POST | `/v1/cpq/quotes/:id/links` | A tracked link to the quote's web view for one recipient (the URL is shown once) | `deals:write` |
| POST | `/v1/cpq/quotes/:id/signature` | Send the approved quote's order form for signature (signers default to the deal's contacts) | `messages:send` |
| GET | `/v1/cpq/quotes/:id/signatures` | Signature requests for the quote, with their status and events | `deals:read` |
| POST | `/v1/cpq/quotes/:id/signed` | Without e-signature: upload the signed order form (PDF); the quote is signed, the deal won and onboarding handed off | `deals:write` |
| POST | `/v1/cpq/quotes/:id/status` | Mark a quote sent, lost or cancelled (a person, from the app or their key) | `deals:write` |
| GET | `/v1/cpq/quotes/:id/views` | What buyers read: opens per recipient, first and last open, time per section and the section read most | `deals:read` |
| POST | `/v1/cpq/replay` | Re-price recent quotes with today's prices and rules, showing what would change (owners) | `settings:write` |
| GET | `/v1/cpq/rules` | Pricing guardrails and approval rules (a starting set is added the first time) | `deals:read` |
| POST | `/v1/cpq/rules` | Add a rule (owners); refused when the check finds an error | `settings:write` |
| PUT | `/v1/cpq/rules/:id` | Change a rule (owners); approvals given under its earlier version no longer count, so open quotes ask again | `settings:write` |
| POST | `/v1/cpq/rules/check` | Check a draft rule set without saving it: problems, test quotes at each rule's boundary, and recent quotes whose approvals would change (owners) | `settings:write` |
| POST | `/v1/cpq/rules/draft` | Draft pricing rules from a policy in plain language, checked for conflicts with test quotes and replay (owners) | `settings:write` |
| GET | `/v1/cpq/settings` | Quoting settings: the order form's seller block and default terms, and the follow-up cadence | `deals:read` |
| PUT | `/v1/cpq/settings` | Change quoting settings (owners) | `settings:write` |

## Examples

### GET /v1/cpq/billing

Billing systems for signed quotes (NetSuite, Metronome, Stripe): connected, on, status and settings; never credentials (owners)

```bash
curl -s "https://api.closefinch.com/v1/cpq/billing" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/billing`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/billing-pushes/$ID/cancel

Withdraw a billing write still waiting for approval (whoever asked, or an owner)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/billing-pushes/$ID/cancel" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/billing-pushes/${id}/cancel`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/billing-pushes/$ID/fail

Fail a billing write stuck running for over 15 minutes; what it had started is marked unknown for a person to check (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/billing-pushes/$ID/fail" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/billing-pushes/${id}/fail`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/billing-pushes/$ID/refresh

Read a written quote's billing state now (orders, invoices, payments, subscription or contract); read only

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/billing-pushes/$ID/refresh" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/billing-pushes/${id}/refresh`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### DELETE /v1/cpq/billing/$VENDOR

Remove a billing system's credentials and turn it off (owners)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/cpq/billing/$VENDOR" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/billing/${vendor}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PUT /v1/cpq/billing/$VENDOR

Connect a billing system with your own account (NetSuite token-based authentication, a Metronome token; Stripe uses your Stripe connection), its mappings, and turn it on or off (owners)

```bash
curl -s -X PUT "https://api.closefinch.com/v1/cpq/billing/$VENDOR" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/billing/${vendor}`, {
  method: "PUT",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/billing/$VENDOR/check

Check a billing system's saved credentials with one read (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/billing/$VENDOR/check" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/billing/${vendor}/check`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/catalog

Products and their current prices

```bash
curl -s "https://api.closefinch.com/v1/cpq/catalog" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/catalog`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/catalog/import/document

Read products and prices from an order form, contract, CRM export or call as a plan with quotes from the source (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/catalog/import/document" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/catalog/import/document`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/catalog/import/sheet

Read a price sheet (.xlsx or .csv) as a plan, each value traced to its row and cell; accept entries to apply them (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/catalog/import/sheet" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/catalog/import/sheet`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/catalog/import/stripe

Read products and prices from your Stripe account (read-only) as a plan; accept entries to apply them (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/catalog/import/stripe" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/catalog/import/stripe`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/contract-periods/$ID/close

Close a period: overage past the credits, and the unused share rolled into the next (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/contract-periods/$ID/close" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/contract-periods/${id}/close`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/contracts

Contracts from signed quotes

```bash
curl -s "https://api.closefinch.com/v1/cpq/contracts" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/contracts`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/cpq/contracts/$ID

A contract with its periods: committed, credits granted, rolled in, used, overage and rolled out

```bash
curl -s "https://api.closefinch.com/v1/cpq/contracts/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/contracts/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/contracts/$ID/usage

Record usage against a contract line (an integration, or a person)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/contracts/$ID/usage" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/contracts/${id}/usage`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/documents/$ID

Download a stored document; its SHA-256 is checked before it's returned

```bash
curl -s "https://api.closefinch.com/v1/cpq/documents/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/documents/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/cpq/drafts

Your open drafts

```bash
curl -s "https://api.closefinch.com/v1/cpq/drafts" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/drafts`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/cpq/drafts/$ID

A draft with its source quotes, confidence and preview

```bash
curl -s "https://api.closefinch.com/v1/cpq/drafts/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/drafts/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/drafts/$ID/accept

Accept a draft you reviewed: a request or structure becomes a draft quote, a change is applied, rules or catalog entries are saved

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/drafts/$ID/accept" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/drafts/${id}/accept`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/drafts/$ID/discard

Discard a draft

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/drafts/$ID/discard" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/drafts/${id}/discard`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/drafts/from-request

Read a request for quote (pasted text, a file, an email or call) or a deal description into catalog line items, priced by the engine; held lines wait for you

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/drafts/from-request" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/drafts/from-request`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/drafts/structure

Propose a deal structure (commit, ramp, expected usage) from the deal's calls and comparable won quotes

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/drafts/structure" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/drafts/structure`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### DELETE /v1/cpq/esign

Disconnect Documenso (owners)

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/cpq/esign" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/esign`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/cpq/esign

Whether Documenso is connected (owners)

```bash
curl -s "https://api.closefinch.com/v1/cpq/esign" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/esign`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PUT /v1/cpq/esign

Connect Documenso (cloud or self-hosted): API URL, token and webhook secret, stored encrypted (owners)

```bash
curl -s -X PUT "https://api.closefinch.com/v1/cpq/esign" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/esign`, {
  method: "PUT",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/intel

Pricing intelligence: win rate by discount band, margin trend, competitors named on the deal and how deals against them ended

```bash
curl -s "https://api.closefinch.com/v1/cpq/intel" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/intel`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### DELETE /v1/cpq/links/$ID

Revoke a tracked link

```bash
curl -s -X DELETE "https://api.closefinch.com/v1/cpq/links/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/links/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/cpq/pipeline

Open quotes: count, value, age, expiry, buyer activity and follow-up state, with who to chase next and why

```bash
curl -s "https://api.closefinch.com/v1/cpq/pipeline" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/pipeline`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PATCH /v1/cpq/prices/$ID

Offer or withdraw a price (owners)

```bash
curl -s -X PATCH "https://api.closefinch.com/v1/cpq/prices/$ID" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/prices/${id}`, {
  method: "PATCH",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/prices/$ID/versions

Change a price: saves its next version (the old one stays, for the quotes priced with it) (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/prices/$ID/versions" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/prices/${id}/versions`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/products

Add a product (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/products" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/products`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### PATCH /v1/cpq/products/$ID

Change a product (owners)

```bash
curl -s -X PATCH "https://api.closefinch.com/v1/cpq/products/$ID" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/products/${id}`, {
  method: "PATCH",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/products/$ID/prices

Add a price to a product (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/products/$ID/prices" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/products/${id}/prices`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes

Quotes, newest change first

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/quotes

Create a quote on a deal; it's priced at once and every number carries its evidence

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID

A quote: lines, every number with its evidence and formula, rules that apply, approvals and versions

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PATCH /v1/cpq/quotes/$ID

Change a quote (send the version you saw); a change to its prices makes earlier approvals stale

```bash
curl -s -X PATCH "https://api.closefinch.com/v1/cpq/quotes/$ID" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}`, {
  method: "PATCH",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/approval

Ask for the approvals this quote needs (the rules decide who; with none needed it's approved at once)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/approval" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/approval`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/approver-context

What an approver sees: rules that fired, totals, versions, earlier decisions, and this buyer's past quotes

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/approver-context" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/approver-context`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/billing

The quote's billing writes: each request, its approval, what was written and read back, and the billing state read since

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/billing" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/billing`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/billing

Ask for a signed quote to be written to a billing system: an owner approves the exact plan in the inbox before anything is written

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/billing" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/billing`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/billing/plan

What a signed quote writes to one billing system, line by line, and anything that stops it (the stored plan while a request is open)

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/billing/plan" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/billing/plan`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/change-request

A change in plain language ("annual, start Oct 15, 15% off seats") as operations, re-priced with today's rules, for you to apply

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/change-request" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/change-request`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/crm-attachment

Attach the signed order form PDF to the deal in each connected CRM (HubSpot, Salesforce), through policy, once each

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/crm-attachment" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/crm-attachment`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/derive

A renewal, amendment, expansion or cancellation quote from a signed one (renewals from live usage; amendments co-terminate)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/derive" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/derive`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/documents

The quote's stored documents (order forms and signed copies) with their hashes

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/documents" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/documents`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/documents

Render the quote's order form as a PDF (stored with its SHA-256; what's signed), a .docx, or a slide outline

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/documents" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/documents`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/followups

The quote's follow-up cadence: each step, when it's due, and what happened

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/followups" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/followups`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/followups/stop

Stop the quote's follow-ups

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/followups/stop" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/followups/stop`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/links

The quote's tracked links

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/links" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/links`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/links

A tracked link to the quote's web view for one recipient (the URL is shown once)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/links" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/links`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/signature

Send the approved quote's order form for signature (signers default to the deal's contacts)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/signature" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/signature`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/signatures

Signature requests for the quote, with their status and events

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/signatures" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/signatures`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/signed

Without e-signature: upload the signed order form (PDF); the quote is signed, the deal won and onboarding handed off

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/signed" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/signed`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/quotes/$ID/status

Mark a quote sent, lost or cancelled (a person, from the app or their key)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/quotes/$ID/status" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/status`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/quotes/$ID/views

What buyers read: opens per recipient, first and last open, time per section and the section read most

```bash
curl -s "https://api.closefinch.com/v1/cpq/quotes/$ID/views" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/quotes/${id}/views`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/replay

Re-price recent quotes with today's prices and rules, showing what would change (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/replay" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/replay`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/rules

Pricing guardrails and approval rules (a starting set is added the first time)

```bash
curl -s "https://api.closefinch.com/v1/cpq/rules" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/rules`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### POST /v1/cpq/rules

Add a rule (owners); refused when the check finds an error

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/rules" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/rules`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### PUT /v1/cpq/rules/$ID

Change a rule (owners); approvals given under its earlier version no longer count, so open quotes ask again

```bash
curl -s -X PUT "https://api.closefinch.com/v1/cpq/rules/$ID" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/rules/${id}`, {
  method: "PUT",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/rules/check

Check a draft rule set without saving it: problems, test quotes at each rule's boundary, and recent quotes whose approvals would change (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/rules/check" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/rules/check`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### POST /v1/cpq/rules/draft

Draft pricing rules from a policy in plain language, checked for conflicts with test quotes and replay (owners)

```bash
curl -s -X POST "https://api.closefinch.com/v1/cpq/rules/draft" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/rules/draft`, {
  method: "POST",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

### GET /v1/cpq/settings

Quoting settings: the order form's seller block and default terms, and the follow-up cadence

```bash
curl -s "https://api.closefinch.com/v1/cpq/settings" \
  -H "Authorization: Bearer $RA_API_KEY"
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/settings`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();
```

### PUT /v1/cpq/settings

Change quoting settings (owners)

```bash
curl -s -X PUT "https://api.closefinch.com/v1/cpq/settings" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
```

```js
const res = await fetch(`https://api.closefinch.com/v1/cpq/settings`, {
  method: "PUT",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}`, "content-type": "application/json" },
  body: JSON.stringify({}), // fields: see the OpenAPI schema
});
const data = await res.json();
```

Request and response schemas: [https://www.closefinch.com/openapi.json](https://www.closefinch.com/openapi.json). All resources: [API reference](https://www.closefinch.com/docs/api).
