Skip to content

Integration guides

Enrich a CSV file

New

Upload a CSV of contacts in the app and download it enriched, or loop over its rows with the API.

Last verified

You have a file of contacts and want it back with profiles, work emails or phone numbers. There are two ways to do it:

  • In the app, no code: Bulk Import takes your CSV and gives you an enriched CSV back.
  • With the API: your code reads the file and calls an endpoint for each row. The API takes JSON, one person per request: there is no endpoint that accepts a CSV file.

Bulk Import in the app

  1. Upload your file. Open Bulk Import and drop a CSV of up to 25,000 rows and 25 MB. You can also paste a list of emails, LinkedIn profile URLs or names instead of uploading a file.
  2. Map your columns. Tell the import which columns hold the LinkedIn profile URL, the email, the first and last name, the company name and the company domain. Common headers such as linkedin_url, email or profile_url are detected for you, and you can change any mapping.
  3. Choose what to look up. Each row can get its full profile, a work email and a phone number. Select one or several.
  4. Review and start. The review step counts the rows that will be enriched, the duplicates and the rows with no usable input, and shows the credits the import reserves before it starts.
  5. Download the result. The job page follows the import row by row. When it completes, you receive an in-app notification and an email, and the enriched CSV is ready to download.

A row needs at least one usable input: a LinkedIn profile URL, an email, or a name with its company. A row that repeats an earlier one is not enriched or charged twice.

What the enriched file contains

The result keeps every column of your file and adds these columns to each row:

ColumnContent
rc_statusenriched, partial, not_found, invalid_input, skipped, insufficient_credits or error
rc_messageWhy a row was not enriched, in plain English
rc_* profile columnsThe fields of the Enrich profile response, one column per field (rc_first_name, rc_current_position_title, rc_location_city...). List fields such as rc_experience hold JSON.
rc_email, rc_email_statusThe work email, when you asked for one
rc_phone, rc_phone_type, rc_phone_statusThe phone number, when you asked for one

partial means some of the requested lookups found a result and others did not. When you ask for contact details without the profile, a single rc_linkedin_url column replaces the profile columns. The file is UTF-8 and opens directly in Excel.

What it costs

You pay only for rows that return a result. A row that is not found, invalid, a duplicate or skipped costs nothing.

LookupCredits per row
Profile from a LinkedIn profile URL1 when found
Profile from a LinkedIn profile URL, with Live enrichment2 when found
Profile from an email or a name2 when found
Work email3 when found
Phone number20 when found

If your balance does not cover every row, the import takes the rows it can afford in file order and marks the others insufficient_credits. Top up and upload those rows again to enrich them.

Live enrichment applies to rows with a LinkedIn profile URL: it scrapes each profile fresh instead of reading the cached profile, and a large file can take several minutes. Bulk Import works during the free trial with your trial credits, except Live enrichment.

Enrich a CSV with the API

Read the file in your code and call, for each row, the endpoint that matches what the row holds:

The row holdsEndpointCredits
A LinkedIn profile URLPOST /v2/fetch/persons1 when found
An email, or a name with its companyPOST /v2/enrich/persons2 when found
You need a work emailPOST /v2/contact/email3 when found
You need a phone numberPOST /v2/contact/phone20 when found

The example below reads contacts.csv, enriches each row from its email column with POST /v2/enrich/persons, and writes contacts_enriched.csv with five profile columns added. A 404 means no match and costs nothing. A 429 means the per-minute rate limit is reached: the example waits the number of seconds in error.details.retryAfter, then retries the same row.

Enrich a CSV

// npm install csv-parse csv-stringify
import { readFileSync, writeFileSync } from "node:fs";
import { parse } from "csv-parse/sync";
import { stringify } from "csv-stringify/sync";

const KEY = "YOUR_API_KEY";
const FIELDS = ["firstName", "lastName", "currentPositionTitle", "currentCompanyName", "linkedinUrl"];

async function enrich(email) {
  while (true) {
    const response = await fetch("https://api.reversecontact.com/v2/enrich/persons", {
      method: "POST",
      headers: { "Authorization": `Bearer ${KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({ email })
    });
    if (response.status === 429) {
      const { error } = await response.json();
      await new Promise((resolve) => setTimeout(resolve, error.details.retryAfter * 1000));
      continue;
    }
    if (response.status === 404) return null;
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return (await response.json()).data.person;
  }
}

const rows = parse(readFileSync("contacts.csv"), { columns: true, bom: true });
for (const row of rows) {
  const person = row.email ? await enrich(row.email) : null;
  for (const field of FIELDS) row[field] = person?.[field] ?? "";
}
writeFileSync("contacts_enriched.csv", stringify(rows, { header: true }));

For a row with a LinkedIn profile URL, call POST /v2/fetch/persons with {"url": ...} instead: it costs 1 credit instead of 2. Work emails and phone numbers are asynchronous: send every row first, keep the webhookId of each request, then collect the results by polling or through webhooks. See Rate limits & credits to size a large file against your per-minute limit.

FAQ

Can I upload a CSV file to the Reverse Contact API?

No. The Reverse Contact API takes JSON, one person per request, and has no endpoint that accepts a CSV file. To enrich a CSV without code, use Bulk Import in the app: upload the file, map its columns and download the enriched CSV. With the API, read the file in your code and call POST /v2/enrich/persons or POST /v2/fetch/persons for each row.

How many rows can Bulk Import enrich at once?

Bulk Import accepts a CSV of up to 25,000 rows and 25 MB per import. Split a larger file into several imports. Each row needs a LinkedIn profile URL, an email, or a name with its company.

How much does it cost to enrich a CSV file?

Bulk Import charges only rows that return a result: 1 credit for a profile found from a LinkedIn profile URL, 2 credits for a profile found from an email or a name, 3 credits for a work email found and 20 credits for a phone number found. Rows that are not found, invalid or duplicated cost nothing.

What does the enriched CSV contain?

The enriched CSV from Bulk Import keeps every column of the original file and adds rc_status, rc_message and one rc_* column per profile field, plus rc_email and rc_phone columns when a work email or a phone number was requested. rc_status tells whether each row was enriched, not found, invalid or skipped.

What happens when my credits run out during a Bulk Import?

Bulk Import reserves credits before the job starts. If the balance does not cover every row, Bulk Import enriches the rows it can afford in file order and marks the other rows insufficient_credits in the enriched CSV, without charging them. Top up and upload those rows again to enrich them.