# API: Calling compliance

| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | `/v1/calling-compliance` | The organization's calling and texting rules: window and states, opt-out scope, replies, disclosures, the DNC registry files, emergency blocks and the state rules table | `settings:read` |
| GET | `/v1/calling-compliance/announcements` | The call announcements, word for word: start (with the recording notice and opt-out), transfer, voicemail drop, recording on and off. Versioned with the disclosures; none can be removed. | `settings:read` |
| POST | `/v1/calling-compliance/check` | Would a text or call to this number be allowed now? Allow, deny or queue (with when), and every reason. Nothing is sent. | `calls:read` |
| GET | `/v1/calling-compliance/consent-wording` | The consent wording each channel shows when someone gives consent (forms, the SMS opt-in), with its version | `settings:read` |
| PUT | `/v1/calling-compliance/consent-wording/:channel` | Reword a channel's consent text (owners; versioned, checked: business name, opt-out, and for SMS help and rates, for calls automated or AI voice and not a condition of purchase) | `settings:write` |
| PUT | `/v1/calling-compliance/disclosure` | Reword the mandatory disclosures (owners). They can't be turned off: each must still name the business, say it's an AI and keep the opt-out. Saved as a new version; marked for counsel review. | `settings:write` |
| GET | `/v1/calling-compliance/disclosure/preview` | What's said or sent first: the voice opening lines, the SMS first-message line, or the email line and sender name | `settings:read` |
| POST | `/v1/calling-compliance/emergencies` | Block calls and texts to states or area codes for a state of emergency (owners; dates inclusive, contact-local) | `settings:write` |
| DELETE | `/v1/calling-compliance/emergencies/:id` | Lift a state-of-emergency block (owners) | `settings:write` |
| GET | `/v1/calling-compliance/opt-out-reviews` | Texts that may be opt-outs, waiting for an owner to decide (oldest first), each with its 10-business-day due date and whether it's overdue | `calls:read` |
| POST | `/v1/calling-compliance/opt-out-reviews/:id` | Decide a held text (owners, from the app; a reason is required and audited): an opt-out (applied under the organization's scope) or not one (the agent may answer again) (web app only) | `settings:write` |
| GET | `/v1/calling-compliance/queue` | The quiet-hours queue: texts and calls held by the calling window, a holiday, an emergency block or a state cap, with why and when each goes (numbers masked) | `calls:read` |
| POST | `/v1/calling-compliance/queue/:id/cancel` | Cancel a held text or call before it's released | `calls:write` |
| POST | `/v1/calling-compliance/queue/:id/unmask` | Show a held item's number in full (owners, from the app; audited) (web app only) | `settings:write` |
| PUT | `/v1/calling-compliance/settings` | Change the rules (owners). The window can be narrowed inside 08:00–20:00 contact-local, never widened; state rules always apply. | `settings:write` |
| GET | `/v1/dnc` | The organization's internal do-not-call list (numbers masked; an owner reveals one from the app, audited) | `calls:read` |
| POST | `/v1/dnc` | Add numbers to the internal do-not-call list (calls and texts stop at once; kept at least five years) | `calls:write` |
| DELETE | `/v1/dnc/:id` | Take a number off the internal do-not-call list (owners; audited). A number they asked to stop stays opted out in the ledger. | `settings:write` |
| POST | `/v1/dnc/:id/unmask` | Show a do-not-call entry's number in full (owners, from the app; audited) (web app only) | `settings:write` |
| GET | `/v1/dnc/registry` | Registry coverage per area code: last refresh, age and whether it's stale (over 31 days) | `settings:read` |
| POST | `/v1/dnc/registry` | Upload the organization's own National Do Not Call Registry download (CSV or text, one number per line; up to 20 MB per upload). Stored hashed per area code. mode=replace (default) clears and refills the area codes it covers; mode=merge adds the next part of the same download (within 24 hours). Refresh at least every 31 days, or marketing calls and texts to those area codes stop. | `settings:write` |
| POST | `/v1/opt-outs` | Record an opt-out someone asked for (by phone, in person, a spoken "don't call me"). Applied at once, under the organization's scope. | `calls:write` |
| POST | `/v1/opt-outs/lift` | Lift an opt-out block on one channel for a number (owners; audited). Texts or calls reopen without counting as their consent; email: the number's opt-out suppression is removed. Their objection stays in the ledger. | `settings:write` |
| GET | `/v1/phone-ledger` | A number's opt-out ledger (STOP, START, HELP, manual and spoken requests) and its consent entries, with the current status per channel | `calls:read` |
| POST | `/v1/phones/:id/unmask` | Show a do-not-call number in full (owners; audited) (web app only) | `settings:write` |
| POST | `/v1/records/:id/unmask-phones` | Show a record's do-not-call phone fields in full (owners; audited) (web app only) | `settings:write` |

## Examples

### GET /v1/calling-compliance

The organization's calling and texting rules: window and states, opt-out scope, replies, disclosures, the DNC registry files, emergency blocks and the state rules table

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

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

### GET /v1/calling-compliance/announcements

The call announcements, word for word: start (with the recording notice and opt-out), transfer, voicemail drop, recording on and off. Versioned with the disclosures; none can be removed.

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

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

### POST /v1/calling-compliance/check

Would a text or call to this number be allowed now? Allow, deny or queue (with when), and every reason. Nothing is sent.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/calling-compliance/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/calling-compliance/consent-wording

The consent wording each channel shows when someone gives consent (forms, the SMS opt-in), with its version

```bash
curl -s "https://api.closefinch.com/v1/calling-compliance/consent-wording" \
  -H "Authorization: Bearer $RA_API_KEY"
```

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

### PUT /v1/calling-compliance/consent-wording/$CHANNEL

Reword a channel's consent text (owners; versioned, checked: business name, opt-out, and for SMS help and rates, for calls automated or AI voice and not a condition of purchase)

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

```js
const res = await fetch(`https://api.closefinch.com/v1/calling-compliance/consent-wording/${channel}`, {
  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();
```

### PUT /v1/calling-compliance/disclosure

Reword the mandatory disclosures (owners). They can't be turned off: each must still name the business, say it's an AI and keep the opt-out. Saved as a new version; marked for counsel review.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/calling-compliance/disclosure`, {
  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/calling-compliance/disclosure/preview

What's said or sent first: the voice opening lines, the SMS first-message line, or the email line and sender name

```bash
curl -s "https://api.closefinch.com/v1/calling-compliance/disclosure/preview" \
  -H "Authorization: Bearer $RA_API_KEY"
```

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

### POST /v1/calling-compliance/emergencies

Block calls and texts to states or area codes for a state of emergency (owners; dates inclusive, contact-local)

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

```js
const res = await fetch(`https://api.closefinch.com/v1/calling-compliance/emergencies`, {
  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/calling-compliance/emergencies/$ID

Lift a state-of-emergency block (owners)

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

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

### GET /v1/calling-compliance/opt-out-reviews

Texts that may be opt-outs, waiting for an owner to decide (oldest first), each with its 10-business-day due date and whether it's overdue

```bash
curl -s "https://api.closefinch.com/v1/calling-compliance/opt-out-reviews" \
  -H "Authorization: Bearer $RA_API_KEY"
```

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

### GET /v1/calling-compliance/queue

The quiet-hours queue: texts and calls held by the calling window, a holiday, an emergency block or a state cap, with why and when each goes (numbers masked)

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

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

### POST /v1/calling-compliance/queue/$ID/cancel

Cancel a held text or call before it's released

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

```js
const res = await fetch(`https://api.closefinch.com/v1/calling-compliance/queue/${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();
```

### PUT /v1/calling-compliance/settings

Change the rules (owners). The window can be narrowed inside 08:00–20:00 contact-local, never widened; state rules always apply.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/calling-compliance/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();
```

### GET /v1/dnc

The organization's internal do-not-call list (numbers masked; an owner reveals one from the app, audited)

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

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

### POST /v1/dnc

Add numbers to the internal do-not-call list (calls and texts stop at once; kept at least five years)

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

```js
const res = await fetch(`https://api.closefinch.com/v1/dnc`, {
  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/dnc/$ID

Take a number off the internal do-not-call list (owners; audited). A number they asked to stop stays opted out in the ledger.

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

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

### GET /v1/dnc/registry

Registry coverage per area code: last refresh, age and whether it's stale (over 31 days)

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

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

### POST /v1/dnc/registry

Upload the organization's own National Do Not Call Registry download (CSV or text, one number per line; up to 20 MB per upload). Stored hashed per area code. mode=replace (default) clears and refills the area codes it covers; mode=merge adds the next part of the same download (within 24 hours). Refresh at least every 31 days, or marketing calls and texts to those area codes stop.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/dnc/registry`, {
  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/opt-outs

Record an opt-out someone asked for (by phone, in person, a spoken "don't call me"). Applied at once, under the organization's scope.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/opt-outs`, {
  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/opt-outs/lift

Lift an opt-out block on one channel for a number (owners; audited). Texts or calls reopen without counting as their consent; email: the number's opt-out suppression is removed. Their objection stays in the ledger.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/opt-outs/lift`, {
  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/phone-ledger

A number's opt-out ledger (STOP, START, HELP, manual and spoken requests) and its consent entries, with the current status per channel

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

```js
const res = await fetch(`https://api.closefinch.com/v1/phone-ledger`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
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).
