# API: People data

| Method | Path | What it does | Scope |
|---|---|---|---|
| GET | `/v1/accounts/:id/headcount` | An account's headcount by function: the latest snapshot per source (PDL estimate, or counted from your CRM's contacts: not complete), each quarter's snapshot and its change against the quarter before | `accounts:read` |
| POST | `/v1/accounts/:id/headcount/snapshot` | Take this month's headcount snapshot now: counted from the CRM, and from PDL when a key is set (one company credit, cached about a month) | `accounts:write` |
| GET | `/v1/job-changes` | Detected job changes (company change, title change, possible departure) with old and new values, each source's evidence and date, the confidence and whether a person needs to confirm it | `signals:read` |
| POST | `/v1/job-changes/:id/confirm` | Confirm a job change: it's applied to the CRM (the new account and contact, the title, a task on the old account when it has an open deal) and counts as a source for re-activation | `signals:write` |
| POST | `/v1/job-changes/:id/dismiss` | Dismiss a job change (it won't be raised again from the same evidence) | `signals:write` |
| POST | `/v1/job-changes/scan` | Look for job changes in the background: bounces, synced mail that isn't private (new addresses, threads, signatures), CRM edits, and PDL for watched people when a key is set; then the re-activation pass. One pass per organization at a time; poll /v1/people-data/pass. | `signals:write` |
| GET | `/v1/people-data/headcount` | Filter accounts by a function's headcount and its change over a window (e.g. engineering, at least 20% growth over 90 days), with the figures, snapshot dates and source | `prospecting:read` |
| POST | `/v1/people-data/import` | Import previewed results into the CRM (an explicit action; audited). Each is deduplicated against existing contacts and accounts by email, LinkedIn and domain: a match is linked and only its empty fields are filled; a person's company is found or created. Importing twice does nothing the second time. | `prospecting:write` |
| GET | `/v1/people-data/pass` | The latest people-data pass (a scan, a re-activation pass or the daily one): queued, running, succeeded or failed | `prospecting:read` |
| POST | `/v1/people-data/search` | Search people or companies in the people and company database (PDL): by a description (compiled like the CRM search), the CRM search's facets, or a query (titles, seniorities, functions, industries, size, places, companies, technologies). Results are previews with each field's source and as-of date and any CRM match; nothing is imported. It runs in the request, so a page is at most 10 records (each record returned costs a credit); the same search within 7 days is free. Without a key: your CRM's matches and what's missing. | `prospecting:write` |
| GET | `/v1/people-data/status` | Whether the people and company database (PDL) is on for this organization, whose key it uses, today's credits and the daily cap, and what works without it | `prospecting:read` |
| GET | `/v1/reactivations` | Past customers' users, lost-deal contacts and engaged buyers found at a new company: why they're watched, the history, how the move was verified, the ICP check, and the drafted re-intro (if any) | `signals:read` |
| POST | `/v1/reactivations/:id/dismiss` | Dismiss a re-activation | `signals:write` |
| POST | `/v1/reactivations/scan` | Queue the re-activation pass over confirmed moves (verify, ICP check, alert the owner, draft a re-intro for approval); poll /v1/people-data/pass | `signals:write` |
| POST | `/v1/records/:id/people-data/enrich` | Look a contact (by email or LinkedIn) or account (by domain) up in the people and company database. A hit or a miss is kept 90 days (never billed twice). With apply, only its empty fields are filled (audited). | `contacts:write` |

## Examples

### GET /v1/accounts/$ID/headcount

An account's headcount by function: the latest snapshot per source (PDL estimate, or counted from your CRM's contacts: not complete), each quarter's snapshot and its change against the quarter before

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

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

### POST /v1/accounts/$ID/headcount/snapshot

Take this month's headcount snapshot now: counted from the CRM, and from PDL when a key is set (one company credit, cached about a month)

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

```js
const res = await fetch(`https://api.closefinch.com/v1/accounts/${id}/headcount/snapshot`, {
  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/job-changes

Detected job changes (company change, title change, possible departure) with old and new values, each source's evidence and date, the confidence and whether a person needs to confirm it

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

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

### POST /v1/job-changes/$ID/confirm

Confirm a job change: it's applied to the CRM (the new account and contact, the title, a task on the old account when it has an open deal) and counts as a source for re-activation

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

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

Dismiss a job change (it won't be raised again from the same evidence)

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

```js
const res = await fetch(`https://api.closefinch.com/v1/job-changes/${id}/dismiss`, {
  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/job-changes/scan

Look for job changes in the background: bounces, synced mail that isn't private (new addresses, threads, signatures), CRM edits, and PDL for watched people when a key is set; then the re-activation pass. One pass per organization at a time; poll /v1/people-data/pass.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/job-changes/scan`, {
  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/people-data/headcount

Filter accounts by a function's headcount and its change over a window (e.g. engineering, at least 20% growth over 90 days), with the figures, snapshot dates and source

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

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

### POST /v1/people-data/import

Import previewed results into the CRM (an explicit action; audited). Each is deduplicated against existing contacts and accounts by email, LinkedIn and domain: a match is linked and only its empty fields are filled; a person's company is found or created. Importing twice does nothing the second time.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/people-data/import`, {
  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/people-data/pass

The latest people-data pass (a scan, a re-activation pass or the daily one): queued, running, succeeded or failed

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

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

### POST /v1/people-data/search

Search people or companies in the people and company database (PDL): by a description (compiled like the CRM search), the CRM search's facets, or a query (titles, seniorities, functions, industries, size, places, companies, technologies). Results are previews with each field's source and as-of date and any CRM match; nothing is imported. It runs in the request, so a page is at most 10 records (each record returned costs a credit); the same search within 7 days is free. Without a key: your CRM's matches and what's missing.

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

```js
const res = await fetch(`https://api.closefinch.com/v1/people-data/search`, {
  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/people-data/status

Whether the people and company database (PDL) is on for this organization, whose key it uses, today's credits and the daily cap, and what works without it

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

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

### GET /v1/reactivations

Past customers' users, lost-deal contacts and engaged buyers found at a new company: why they're watched, the history, how the move was verified, the ICP check, and the drafted re-intro (if any)

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

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

### POST /v1/reactivations/$ID/dismiss

Dismiss a re-activation

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

```js
const res = await fetch(`https://api.closefinch.com/v1/reactivations/${id}/dismiss`, {
  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/reactivations/scan

Queue the re-activation pass over confirmed moves (verify, ICP check, alert the owner, draft a re-intro for approval); poll /v1/people-data/pass

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

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

Look a contact (by email or LinkedIn) or account (by domain) up in the people and company database. A hit or a miss is kept 90 days (never billed twice). With apply, only its empty fields are filled (audited).

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

```js
const res = await fetch(`https://api.closefinch.com/v1/records/${id}/people-data/enrich`, {
  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();
```

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