---
title: "Bulk enrich people"
method: POST
path: "/v2/bulk"
tags: ["Bulk"]
---

# Bulk enrich people

`POST /v2/bulk`

## Request

- Base URL: `https://api.reversecontact.com`
- URL: `https://api.reversecontact.com/v2/bulk`
- Auth: HTTP bearer

Enriches up to 25,000 people in one call. Each item is what /v2/enrich/persons (email, or name with a company) or /v2/fetch/persons (LinkedIn URL) takes, priced like it. The credits of every item are reserved at once, up to the balance (items past it read insufficient_credits and cost nothing), and given back for what is not found. Duplicates of an earlier item are enriched once and cost nothing. Answers 202 at once with the task: follow it at links.self (wait=N holds the request until it settles), or pass webhookUrl to receive one POST when it settles; once it is completed or cancelled, links.results gives the results CSV, one row per item in the order sent. families adds the contact finders (contact_email, contact_phone) and needs their permission; emailType chooses the kind of email. A field the body or an item does not define is refused with 422 UNKNOWN_FIELD (the field, the one it most likely stands for, the accepted fields), never ignored: the task would otherwise run without it. An API key with credit limits must hold the whole reservation: a task that would take it over its daily, monthly or total limit is refused with KEY_CREDIT_LIMIT_REACHED before anything is reserved, and a started task counts against the key what it reserved, then only what it spent once it settles. Following a task, cancelling it and downloading its results stay open at a zero balance. Credits: the unit price of each item, as /v2/enrich/persons, /v2/fetch/persons and /v2/contact/*. The request itself is free.

## Headers

- `Idempotency-Key` string: Optional. A key you choose (1 to 255 printable ASCII characters, a UUID for example) that makes the request safe to retry. For 24 hours, a request with the same key and the same body returns the first response with Idempotent-Replayed: true, without starting another lookup or debiting credits.

## Request body

- object
  - `items` object[], required
    - `linkedinUrl` string: Person LinkedIn URL (read from saved data unless live is true)
    - `email` string: Email address
    - `firstName` string: First name
    - `lastName` string: Last name
    - `companyDomain` string: Company domain (e.g. acme.com)
    - `companyName` string: Company name (alternative to domain)
    - `externalId` string: Your own identifier, given back in its row of the results CSV
  - `families` string[]: What to look up for each item (default: profile)
  - `emailType` 'professional' | 'personal' | 'any': With contact_email: the kind of email to look for
  - `live` boolean: Scrape LinkedIn URL items live instead of reading saved data (default false)
  - `taskName` string: A name for the task history (default: Sent via API)
  - `webhookUrl` string, uri: Public HTTPS URL that receives one POST when the task settles: { event: task.updated, taskId, type, status, pollUrl, resultsUrl, occurredAt }. It carries no results. A failed POST (timeout, network error, 408, 429, 5xx) is retried for about 3 hours, so the same event can arrive twice: key it on taskId and status.

## Response `202`

Bulk enrich task created

- object
  - `success` true, required
  - `data` object, required
    - `task` object, required
      - `id` string, uuid, required: Task id
      - `type` 'enrich_persons' | 'list_import' | 'list_enrich' | 'list_search_import' | 'search_export', required: enrich_persons: a Bulk enrich task (POST /v2/bulk, or a file from the dashboard). list_import: Signals or a file imported into a List. list_enrich: data fetched for List members. list_search_import: a Search added to a List. search_export: a Search exported as a file.
      - `entity` 'persons' | 'companies', required
      - `status` 'queued' | 'running' | 'paused' | 'completed' | 'cancelled' | 'failed', required: queued and running still move (read it again, or wait=N); paused waits for someone to resume it; completed, cancelled and failed are final.
      - `source` 'api' | 'mcp' | 'ask' | 'dashboard', nullable, required: Who started it: an API key, an AI assistant (MCP), Ask, or the dashboard. null for a task created before sources were recorded.
      - `taskName` string, required: The file name, or the taskName given at creation
      - `listId` string, uuid, nullable, required: The List a List task works on
      - `progress` object, required
        - `total` integer, required: Items in the task
        - `processed` integer, required: Items done
        - `succeeded` integer, required: Items that delivered
        - `failed` integer, required: Items that did not (not found, invalid, error)
        - `skipped` integer, required: Items not run (duplicates, no usable input, out of credits, cancelled)
        - `remaining` integer, required: Items left
      - `credits` object, required
        - `estimated` integer, required: Credits reserved when the task was created (0 when nothing is reserved up front)
        - `used` integer, nullable, required: Credits spent, once the task has settled them
      - `estimatedSecondsRemaining` integer, nullable, required: Seconds left from the task's recent pace, while it runs; null when unknown
      - `error` object, nullable, required
        - `code` string, required: Why the task failed
      - `createdAt` string, date-time, required: ISO 8601
      - `startedAt` string, date-time, nullable, required: ISO 8601
      - `completedAt` string, date-time, nullable, required: ISO 8601
      - `links` object, required
        - `self` string, required: Reads this task (wait=N holds the request until it settles)
        - `results` string, nullable, required: Its results CSV, set once the task is completed or cancelled (enrich_persons tasks)
        - `operation` string, nullable, required: The List operation it runs as (List tasks)
    - `duplicateCount` integer, required: Items that repeat an earlier one
    - `creditsEstimated` integer, required: Credits reserved
    - `notRunForCredits` integer, required: Items the balance could not cover
  - `error` unknown, required
  - `quotas` V2Quotas, required
    - `creditsConsumed` number, required: Credits used for this request after pricing resolution
    - `workspace` object, required
      - `id` string, required: Workspace identifier
      - `credits` V2Credits, required
        - `total` number, required: Total credits in your plan
        - `used` number, required: Credits consumed so far
        - `left` number, required: Remaining credits
      - `hasUnlimitedCredits` boolean, required: Whether workspace credits are unlimited
      - `allowDailyOvercost` boolean, required: Whether the workspace may exceed its daily cap (Enterprise only)
      - `dailyLimit` V2LimitInfo
        - `limit` integer, required: Maximum allowed in the window
        - `used` integer, required: Amount used in the window
        - `left` integer, required: Remaining in the window
        - `nextReset` string, required: When the window resets (ISO 8601)
      - `minuteRateLimit` V2LimitInfo, required
        - `limit` integer, required: Maximum allowed in the window
        - `used` integer, required: Amount used in the window
        - `left` integer, required: Remaining in the window
        - `nextReset` string, required: When the window resets (ISO 8601)
    - `key` object, nullable, required
      - `id` string, required: API key identifier
      - `dailyLimit` V2LimitInfo
        - `limit` integer, required: Maximum allowed in the window
        - `used` integer, required: Amount used in the window
        - `left` integer, required: Remaining in the window
        - `nextReset` string, required: When the window resets (ISO 8601)
      - `minuteRateLimit` V2LimitInfo, required
        - `limit` integer, required: Maximum allowed in the window
        - `used` integer, required: Amount used in the window
        - `left` integer, required: Remaining in the window
        - `nextReset` string, required: When the window resets (ISO 8601)
      - `creditLimits` object, required: Credit limits set on this API key. Each is null when the key has no such limit.
        - `daily` V2KeyCreditLimit, required
          - `limit` number, required: Credits this key may spend in the period
          - `used` number, required: Credits this key spent in the period, this request included
          - `left` number, required: Credits this key may still spend in the period
          - `nextReset` string, nullable, required: When the period resets (ISO 8601): 00:00 UTC for the daily limit, the 1st of next month at 00:00 UTC for the monthly limit, null for the total limit
        - `monthly` V2KeyCreditLimit, required
          - `limit` number, required: Credits this key may spend in the period
          - `used` number, required: Credits this key spent in the period, this request included
          - `left` number, required: Credits this key may still spend in the period
          - `nextReset` string, nullable, required: When the period resets (ISO 8601): 00:00 UTC for the daily limit, the 1st of next month at 00:00 UTC for the monthly limit, null for the total limit
        - `total` V2KeyCreditLimit, required
          - `limit` number, required: Credits this key may spend in the period
          - `used` number, required: Credits this key spent in the period, this request included
          - `left` number, required: Credits this key may still spend in the period
          - `nextReset` string, nullable, required: When the period resets (ISO 8601): 00:00 UTC for the daily limit, the 1st of next month at 00:00 UTC for the monthly limit, null for the total limit
  - `metadata` V2Metadata, required
    - `requestId` string, required: Unique identifier for this request
    - `executionTimeMs` integer, required: Total execution time in milliseconds
    - `updatedAt` string: Last upstream update timestamp (ISO 8601). Present only when available.

## Other responses

- `400`: Invalid JSON body or endpoint-specific business validation, or an Idempotency-Key that is not 1 to 255 printable ASCII characters (INVALID_IDEMPOTENCY_KEY)
- `409`: IDEMPOTENCY_KEY_IN_USE: a request with the same Idempotency-Key is still being processed. Retry after the Retry-After seconds to receive its response.
- `422`: Schema or validation error, unresolved internal id, or disposable email domain, or an Idempotency-Key already used with a different body (IDEMPOTENCY_KEY_REUSED)

---

[API](https://skmtc.dev/scrapin/apis/reverse-contact-api.md) - [All operations](https://skmtc.dev/scrapin/apis/reverse-contact-api/llms.txt) - [OpenAPI document](https://skmtc.dev/scrapin/apis/reverse-contact-api/revisions/7d02242af2a9?raw)
