lists scope. Enrichment spends credits; the rest of this page, including CRM pushes, does not.
Enrich the contacts you have
POST /business/lists/{listId}/enrich fills in missing contact details for a list you already built. mode decides what runs:
limit is how many rows to take, in the list’s default order (oldest first) after any filters. It is required unless you name the contacts with contactIds (up to 500 row ids from the list). validate_emails and demographics process at most 5,000 rows: a larger limit is accepted, but only the first 5,000 rows are taken.
Rows that already hold the data you asked for, or were searched for it before, are skipped and not charged, but they still count toward limit. So the same call made twice takes the same rows; to go further down the list, see Work through a long list.
It answers 202 and works in the background. totalContacts is the number of rows this run takes (fewer than limit near the end of the list) and estimatedMinutes roughly how long it runs.
Follow the enrichment job
The three finding modes (email, phone, phone_and_email) run as a job, and the 202 carries its jobId and status:
pending: the job is waiting. Your enrichment jobs run one at a time, whether you started them here or in the app.processing: the job is running.
GET /business/jobs/{jobId} for its status, its counts and the credits it has charged so far. Long-running work shows the response and what each status means.
Sending the same request again while its job is still queued or running (same mode, filters, offset and limit) returns that job instead of starting another.
validate_emails and demographics do not return a job. Follow the list’s completionStatus instead.
Work through a long list
A call withoutoffset always starts at the list’s first row. To work through a long list in batches, pass offset as the previous call’s offset plus its limit:
offset counts rows after filters, and works with the three finding modes only. It cannot be combined with contactIds.
If the balance runs out
Before a finding job starts, the balance must cover every contact it takes at the highest price it could cost: 50 per email (100 when personal emails are prioritised), 200 per phone, 250 for both. Otherwise the call answers402 INSUFFICIENT_CREDITS. Most contacts then cost less, because you pay only for what is found. If credits still run out while the job runs (for example, because other work spent them meanwhile), the job pauses: its status turns stopped, with pausedReason: "INSUFFICIENT_CREDITS". Everything it found before the pause stays on the list. Top up, then resume it from the list’s page in the app. The API cannot resume or cancel a job.
Enrich only the rows you choose
The three finding modes also takefilters, the same row filter GET /business/lists/{listId}/rows uses. This enriches only the rows a smart column marked as a fit:
filters and contactIds cannot be combined, and neither works with validate_emails or demographics. The qualify leads workflow uses this pattern end to end.
Enrichment bills per contact enriched, not per contact attempted: a contact whose email cannot be found does not cost. A work email costs 20 credits when Fuse’s own data finds it and 50 when a partner provider does, a phone 200, a re-verified email 10 and a demographics match 1. Contacts that already carry the data are never charged again. Credits has every price. A list with nothing left to find answers
409 ALL_CONTACTS_ALREADY_ENRICHED. Check the balance with GET /business/credits first for a large list.Copy rows into another list
POST /business/lists/save-to-list copies rows from one list into another. sourceListId and limit are both required, so a copy is always bounded. The copy does not enrich: run POST /business/lists/{listId}/enrich on the destination afterwards if the rows need emails or phones.
listId, or pass listName to create one. Add filters to copy only the rows that match — the same row filters GET /business/lists/{listId}/rows takes.
The copy adds the same contacts to the destination rather than creating new ones, so anything you later enrich on either list shows on both. Custom and smart column values belong to the list they were written on and are not copied.
Turn contacts into companies
POST /business/lists/{listId}/derive-company-list builds a company list from the employers of a contact list. Send the new list’s name (required, 1 to 255 characters; a name already in use answers 409 LIST_NAME_TAKEN).
202 and fills the company list in the background, so follow the new list’s completionStatus:
sourceContacts is how many contacts were read, not how many companies came out — several contacts usually collapse into one company. Useful when a person-level search has found the right accounts and you now want to work them at company level.
Commit an import
A file import is a two-step, and only the second step writes anything.POST /business/imports parses the file, answers the detected headers with a suggestedMapping, and stores that suggestion; it never commits, and a destination sent with it is refused. POST /business/imports/{importId}/commit runs the import into a list.
mapping entry first, then the stored suggestion, then the standard header names (email, first_name, title, domain, url, position and the like). A value in mapping must be one of the template labels; anything else is 422 VALIDATION_FAILED rather than a silently dropped column. A file in which no column resolves to LinkedIn URL, Email, or a name plus Company Domain is refused with 422 IMPORT_IDENTITY_MISSING, because its rows could not be matched against the list.
202 echoes the mapping the import ran with and lists the ignoredHeaders it dropped. Its jobId is a UUID that GET /business/jobs/{jobId} cannot read — follow the destination list instead.
A row that matches a contact already in the destination list (by LinkedIn URL, then email, then name plus company domain) is handled by onDuplicate:
With
enrich set to anything but none, merge and replace both enrich the existing contact in place, and skip leaves it out of the enrichment.
Push to your CRM
POST /business/lists/{listId}/crm-push sends a list’s contacts into a connected CRM. crm is required: hubspot, salesforce, zoho, attio or pipedrive.
202 and pushes in the background:
contactIds (up to 500) to push only those contacts instead, which also overwrites fields on existing records. The CRM has to be connected already, or the call answers 422 CRM_NOT_CONNECTED; see CRM sync. A company list answers 422 CONTACT_LIST_REQUIRED.
Organise with folders
Folders group lists, campaigns or agents of one kind, and the kinds do not mix:contactList, companyList, campaign, agent.
Deleting a folder never deletes lists. They move back to the root, so a folder is safe to remove once you have stopped using it.
Fix one contact
Two calls work on a single contact rather than a whole list:PATCH /business/contacts/{contactId} sets which address or number is the primary one, when a contact has several:
GET /business/contacts/{contactId}/activities returns that contact’s timeline — what was sent, opened, replied and called, newest activity paged with limit and cursor: