Skip to content

API reference

API: Enrichment

Markdown version

MethodPathWhat it doesScope
GET/v1/enrichment/callsThe enrichment ledger: every step (vendor call, cached answer, in-house step, skip) with its fields, outcome, cost and approverprospecting:read
GET/v1/enrichment/policyThe enrichment policy: the waterfall order per field, allowed vendors and fields, caps (per record, run and month), the approval threshold, cache days and prices; each paid vendor's state (keys are never shown)prospecting:read
PUT/v1/enrichment/policyChange the enrichment policy (owner): waterfall order per field, vendors and fields allowed, caps, approval threshold, cache days, pricessettings:write
GET/v1/enrichment/runsEnrichment runs, newest first (including runs waiting for an owner's approval)prospecting:read
POST/v1/enrichment/runsSet up a bulk enrichment run over records or a list (up to 10,000). Returns the cost estimate; nothing runs until it's startedprospecting:write
GET/v1/enrichment/runs/:idA run: status, estimate, budget and spend, counts, approvalprospecting:read
POST/v1/enrichment/runs/:id/approveApprove a run's paid enrichment (owner): it's queued with a budget covering its upper estimatesettings:write
POST/v1/enrichment/runs/:id/rejectDecline a run's paid enrichment (owner)settings:write
POST/v1/enrichment/runs/:id/startStart a run: queued, or waiting for an owner's approval when the estimate passes the approval threshold or the monthly capprospecting:write
POST/v1/enrichment/runs/:id/stopStop a runprospecting:write
POST/v1/phones/:id/lookupQueue a line lookup (Telnyx Number Lookup: line type and validity). Off until a key is set; a lookup within 30 days isn't billed againcontacts:write
POST/v1/phones/:id/outcomesLog a call's outcome on a number (connected, voicemail, no answer, busy, disconnected, wrong number); the ranking and dead flag are recomputedcontacts:write
POST/v1/phones/:id/reviveClear a dead flag: earlier outcomes stop counting and the state goes back to the format checkcontacts:write
GET/v1/records/:id/best-numbersThe record's numbers ranked by how likely each is to connect (line type, state, source, its own call outcomes), each with the reason and last outcomes; dead numbers flagged and never ranked. Recomputed on read.prospecting:read
POST/v1/records/:id/enrichEnrich this record's empty fields in the background (a one-record run; it waits for an owner when the estimate passes the caps)prospecting:write
GET/v1/records/:id/enrichmentA contact's, lead's or account's enrichment: each enriched field's provenance (provider, date, confidence, cost, source), guesses and not-found fields, which fields are empty, and the latest stepsprospecting:read
POST/v1/records/:id/enrichment/previewWhat enriching this record's empty fields could cost (no call is made): the vendors it would reach, cached answers, at most and likely cost, and whether an owner must approveprospecting:read
GET/v1/sheetsSheets (list workspaces), newest firstprospecting:read
POST/v1/sheetsA sheet over a list or a search: the first 500 rows now, up to 10,000 in the backgroundprospecting:write
DELETE/v1/sheets/:idDelete a sheet (its rows and cells; CRM records stay)prospecting:write
GET/v1/sheets/:idA sheet with its columns and its latest runsprospecting:read
PATCH/v1/sheets/:id/cellsSet a cell by hand (audited with its earlier value)prospecting:write
POST/v1/sheets/:id/columnsAdd a column: a CRM field, an enrichment field (filled through the waterfall), or an AI column (name, instruction, output type)prospecting:write
DELETE/v1/sheets/:id/columns/:columnRemove a column and its cellsprospecting:write
GET/v1/sheets/:id/exportThe sheet as CSV (each column with its source)prospecting:read
POST/v1/sheets/:id/moreLoad more: the next 10,000 matches of the sheet's list or search, in the backgroundprospecting:write
POST/v1/sheets/:id/pushPush to a CRM list: matched rows join a new static list; with create_unmatched, unmatched rows become records first (at most 2,000)prospecting:write
GET/v1/sheets/:id/rowsA page of rows (up to 200) with their CRM fields and each cell's value, status and sourceprospecting:read
POST/v1/sheets/:id/runsSet up a column run (enrichment and AI columns over all rows, rows not yet filled, or unmatched CSV rows) with its cost estimate; start it with /v1/enrichment/runs/:id/startprospecting:write
POST/v1/sheets/csvA sheet from a CSV (up to 10,000 rows): rows kept as uploaded, matched to the CRM by email, domain or LinkedIn in a job (match rate reported, unmatched rows kept); asked-for columns are then enriched for the unmatched rows as a runprospecting:write
POST/v1/sheets/vibe"Vibe campaign" (our reading, marked as an assumption): describe a campaign; get a sheet from the search it compiles to, with suggested columns (not run until started). Nothing is sent.prospecting:write

Examples

GET /v1/enrichment/calls

The enrichment ledger: every step (vendor call, cached answer, in-house step, skip) with its fields, outcome, cost and approver

curl -s "https://api.closefinch.com/v1/enrichment/calls" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/enrichment/calls`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

GET /v1/enrichment/policy

The enrichment policy: the waterfall order per field, allowed vendors and fields, caps (per record, run and month), the approval threshold, cache days and prices; each paid vendor's state (keys are never shown)

curl -s "https://api.closefinch.com/v1/enrichment/policy" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/enrichment/policy`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

PUT /v1/enrichment/policy

Change the enrichment policy (owner): waterfall order per field, vendors and fields allowed, caps, approval threshold, cache days, prices

curl -s -X PUT "https://api.closefinch.com/v1/enrichment/policy" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/enrichment/policy`, {
  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/enrichment/runs

Enrichment runs, newest first (including runs waiting for an owner's approval)

curl -s "https://api.closefinch.com/v1/enrichment/runs" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/enrichment/runs`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

POST /v1/enrichment/runs

Set up a bulk enrichment run over records or a list (up to 10,000). Returns the cost estimate; nothing runs until it's started

curl -s -X POST "https://api.closefinch.com/v1/enrichment/runs" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/enrichment/runs`, {
  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/enrichment/runs/$ID

A run: status, estimate, budget and spend, counts, approval

curl -s "https://api.closefinch.com/v1/enrichment/runs/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/enrichment/runs/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

POST /v1/enrichment/runs/$ID/approve

Approve a run's paid enrichment (owner): it's queued with a budget covering its upper estimate

curl -s -X POST "https://api.closefinch.com/v1/enrichment/runs/$ID/approve" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/enrichment/runs/${id}/approve`, {
  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/enrichment/runs/$ID/reject

Decline a run's paid enrichment (owner)

curl -s -X POST "https://api.closefinch.com/v1/enrichment/runs/$ID/reject" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/enrichment/runs/${id}/reject`, {
  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/enrichment/runs/$ID/start

Start a run: queued, or waiting for an owner's approval when the estimate passes the approval threshold or the monthly cap

curl -s -X POST "https://api.closefinch.com/v1/enrichment/runs/$ID/start" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/enrichment/runs/${id}/start`, {
  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/enrichment/runs/$ID/stop

Stop a run

curl -s -X POST "https://api.closefinch.com/v1/enrichment/runs/$ID/stop" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/enrichment/runs/${id}/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();

POST /v1/phones/$ID/lookup

Queue a line lookup (Telnyx Number Lookup: line type and validity). Off until a key is set; a lookup within 30 days isn't billed again

curl -s -X POST "https://api.closefinch.com/v1/phones/$ID/lookup" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/phones/${id}/lookup`, {
  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/phones/$ID/outcomes

Log a call's outcome on a number (connected, voicemail, no answer, busy, disconnected, wrong number); the ranking and dead flag are recomputed

curl -s -X POST "https://api.closefinch.com/v1/phones/$ID/outcomes" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/phones/${id}/outcomes`, {
  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/phones/$ID/revive

Clear a dead flag: earlier outcomes stop counting and the state goes back to the format check

curl -s -X POST "https://api.closefinch.com/v1/phones/$ID/revive" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/phones/${id}/revive`, {
  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/best-numbers

The record's numbers ranked by how likely each is to connect (line type, state, source, its own call outcomes), each with the reason and last outcomes; dead numbers flagged and never ranked. Recomputed on read.

curl -s "https://api.closefinch.com/v1/records/$ID/best-numbers" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/records/${id}/best-numbers`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

POST /v1/records/$ID/enrich

Enrich this record's empty fields in the background (a one-record run; it waits for an owner when the estimate passes the caps)

curl -s -X POST "https://api.closefinch.com/v1/records/$ID/enrich" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/records/${id}/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();

GET /v1/records/$ID/enrichment

A contact's, lead's or account's enrichment: each enriched field's provenance (provider, date, confidence, cost, source), guesses and not-found fields, which fields are empty, and the latest steps

curl -s "https://api.closefinch.com/v1/records/$ID/enrichment" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/records/${id}/enrichment`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

POST /v1/records/$ID/enrichment/preview

What enriching this record's empty fields could cost (no call is made): the vendors it would reach, cached answers, at most and likely cost, and whether an owner must approve

curl -s -X POST "https://api.closefinch.com/v1/records/$ID/enrichment/preview" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/records/${id}/enrichment/preview`, {
  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/sheets

Sheets (list workspaces), newest first

curl -s "https://api.closefinch.com/v1/sheets" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/sheets`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

POST /v1/sheets

A sheet over a list or a search: the first 500 rows now, up to 10,000 in the background

curl -s -X POST "https://api.closefinch.com/v1/sheets" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets`, {
  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/sheets/$ID

Delete a sheet (its rows and cells; CRM records stay)

curl -s -X DELETE "https://api.closefinch.com/v1/sheets/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

GET /v1/sheets/$ID

A sheet with its columns and its latest runs

curl -s "https://api.closefinch.com/v1/sheets/$ID" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

PATCH /v1/sheets/$ID/cells

Set a cell by hand (audited with its earlier value)

curl -s -X PATCH "https://api.closefinch.com/v1/sheets/$ID/cells" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/cells`, {
  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/sheets/$ID/columns

Add a column: a CRM field, an enrichment field (filled through the waterfall), or an AI column (name, instruction, output type)

curl -s -X POST "https://api.closefinch.com/v1/sheets/$ID/columns" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/columns`, {
  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/sheets/$ID/columns/$COLUMN

Remove a column and its cells

curl -s -X DELETE "https://api.closefinch.com/v1/sheets/$ID/columns/$COLUMN" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/columns/${column}`, {
  method: "DELETE",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

GET /v1/sheets/$ID/export

The sheet as CSV (each column with its source)

curl -s "https://api.closefinch.com/v1/sheets/$ID/export" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/export`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

POST /v1/sheets/$ID/more

Load more: the next 10,000 matches of the sheet's list or search, in the background

curl -s -X POST "https://api.closefinch.com/v1/sheets/$ID/more" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/more`, {
  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/sheets/$ID/push

Push to a CRM list: matched rows join a new static list; with create_unmatched, unmatched rows become records first (at most 2,000)

curl -s -X POST "https://api.closefinch.com/v1/sheets/$ID/push" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/push`, {
  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/sheets/$ID/rows

A page of rows (up to 200) with their CRM fields and each cell's value, status and source

curl -s "https://api.closefinch.com/v1/sheets/$ID/rows" \
  -H "Authorization: Bearer $RA_API_KEY"
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/rows`, {
  method: "GET",
  headers: { authorization: `Bearer ${process.env.RA_API_KEY}` },
});
const data = await res.json();

POST /v1/sheets/$ID/runs

Set up a column run (enrichment and AI columns over all rows, rows not yet filled, or unmatched CSV rows) with its cost estimate; start it with /v1/enrichment/runs/:id/start

curl -s -X POST "https://api.closefinch.com/v1/sheets/$ID/runs" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets/${id}/runs`, {
  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/sheets/csv

A sheet from a CSV (up to 10,000 rows): rows kept as uploaded, matched to the CRM by email, domain or LinkedIn in a job (match rate reported, unmatched rows kept); asked-for columns are then enriched for the unmatched rows as a run

curl -s -X POST "https://api.closefinch.com/v1/sheets/csv" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets/csv`, {
  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/sheets/vibe

"Vibe campaign" (our reading, marked as an assumption): describe a campaign; get a sheet from the search it compiles to, with suggested columns (not run until started). Nothing is sent.

curl -s -X POST "https://api.closefinch.com/v1/sheets/vibe" \
  -H "Authorization: Bearer $RA_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'
const res = await fetch(`https://api.closefinch.com/v1/sheets/vibe`, {
  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. All resources: API reference.

Send feedback

Tell us what's broken, confusing or missing on this page, or an idea. It goes to the team that builds the product.

Please don't include passwords or card numbers.
Only to reply about this. Never added to any mailing list.