# API: Freshness

| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | `/v1/email-verification` | An address's cached verification (state, each check, when) and its bounce history | `contacts:read` |
| POST | `/v1/email-verification/bounces` | Report a bounce of one of your sends (e.g. from your sending provider). Soft bounces: crm:write. A hard bounce suppresses the address everywhere, so it needs an owner (org:write). Who reported it is recorded. | `contacts:write` |
| GET | `/v1/email-verification/settings` | The catch-all policy (block, reduce: allow at a reduced daily volume, second_signal: allow only with a second sign the address is real), the reduced-volume cap and how long each result is reused | `contacts:read` |
| PUT | `/v1/email-verification/settings` | Set the catch-all policy, the reduced-volume cap and the cache TTLs (owner; audited) | `settings:write` |
| DELETE | `/v1/email-verification/suppressions` | Lift an address's suppression (owner; audited). Its next verification runs fresh. | `settings:write` |
| POST | `/v1/email-verification/verify` | Verify an address now (in-house checks, bounce history, and MillionVerifier when a key is set; a fresh cached result is reused unless max_age_days says otherwise), with the send decision | `contacts:write` |
| GET | `/v1/freshness/settings` | How long each kind of field stays fresh (days), the pre-send email window and the cited-fact window | `contacts:read` |
| PUT | `/v1/freshness/settings` | Change the freshness TTLs and windows, or turn read-time re-checks off (owner) | `settings:write` |
| DELETE | `/v1/phones/:id` | Remove a phone number | `contacts:write` |
| PATCH | `/v1/phones/:id` | Override a number's state or type (recorded as set by a person), or hand its state back to the format check | `contacts:write` |
| GET | `/v1/records/:id/freshness` | When each checked field (email, phone, domain, title, firmographics) was last verified or written, which are stale, and whether a re-check is queued. Reading it queues a re-check of stale ones, like reading the record. | `contacts:read` |
| POST | `/v1/records/:id/freshness/recheck` | Re-check this record's email, phone and domain now with the in-house checks (syntax, MX/null MX, disposable and role addresses; phone format and country; domain resolves). Free; audited. | `contacts:write` |
| GET | `/v1/records/:id/phones` | A contact's, lead's or account's phone numbers: E.164, type, state (valid, invalid, unknown), why, source and when checked. Invalid ones are not dialable. | `contacts:read` |
| POST | `/v1/records/:id/phones` | Add a phone number by hand. It's normalised to E.164 and given a state by the in-house format and country check (or the state you set). The same number twice is one entry. | `contacts:write` |
| GET | `/v1/send-checks/:run_id` | The latest pre-send check of a drafted email: each recipient's verification and each cited fact (still on its page, gone, changed or unreachable) | `agents:read` |
| POST | `/v1/send-checks/:run_id` | Check a drafted email now: re-verify stale recipient addresses and re-read the cited sources (each quote must still be there). The send runs the same check again right before sending. | `approvals:write` |
| POST | `/v1/send-checks/:run_id/acknowledge` | The sender confirms a changed fact is out of the draft (or still right): it stops blocking the send. Recorded with who and when. (web app only) | `approvals:write` |
| POST | `/v1/send-checks/:run_id/redraft` | Re-draft the email without the facts that changed (AI): the waiting item is rejected and a new one waits for your approval (web app only) | `approvals:write` |

## Examples

### GET /v1/email-verification

An address's cached verification (state, each check, when) and its bounce history

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

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

### POST /v1/email-verification/bounces

Report a bounce of one of your sends (e.g. from your sending provider). Soft bounces: crm:write. A hard bounce suppresses the address everywhere, so it needs an owner (org:write). Who reported it is recorded.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/email-verification/bounces`, {
  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/email-verification/settings

The catch-all policy (block, reduce: allow at a reduced daily volume, second_signal: allow only with a second sign the address is real), the reduced-volume cap and how long each result is reused

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

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

### PUT /v1/email-verification/settings

Set the catch-all policy, the reduced-volume cap and the cache TTLs (owner; audited)

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

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

### DELETE /v1/email-verification/suppressions

Lift an address's suppression (owner; audited). Its next verification runs fresh.

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

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

### POST /v1/email-verification/verify

Verify an address now (in-house checks, bounce history, and MillionVerifier when a key is set; a fresh cached result is reused unless max_age_days says otherwise), with the send decision

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

```js
const res = await fetch(`https://api.closefinch.com/v1/email-verification/verify`, {
  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/freshness/settings

How long each kind of field stays fresh (days), the pre-send email window and the cited-fact window

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

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

### PUT /v1/freshness/settings

Change the freshness TTLs and windows, or turn read-time re-checks off (owner)

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

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

### DELETE /v1/phones/$ID

Remove a phone number

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

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

### PATCH /v1/phones/$ID

Override a number's state or type (recorded as set by a person), or hand its state back to the format check

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

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

### GET /v1/records/$ID/freshness

When each checked field (email, phone, domain, title, firmographics) was last verified or written, which are stale, and whether a re-check is queued. Reading it queues a re-check of stale ones, like reading the record.

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

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

### POST /v1/records/$ID/freshness/recheck

Re-check this record's email, phone and domain now with the in-house checks (syntax, MX/null MX, disposable and role addresses; phone format and country; domain resolves). Free; audited.

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

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

A contact's, lead's or account's phone numbers: E.164, type, state (valid, invalid, unknown), why, source and when checked. Invalid ones are not dialable.

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

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

### POST /v1/records/$ID/phones

Add a phone number by hand. It's normalised to E.164 and given a state by the in-house format and country check (or the state you set). The same number twice is one entry.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/records/${id}/phones`, {
  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/send-checks/$RUN_ID

The latest pre-send check of a drafted email: each recipient's verification and each cited fact (still on its page, gone, changed or unreachable)

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

```js
const res = await fetch(`https://api.closefinch.com/v1/send-checks/${run_id}`, {
  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).
