Skip to content

MaintenanceThe former company search endpoint goes into maintenance on November 9Migration guide

Endpoints // Lists

Add members

New

Last verified

Available inAPIMCPSDKCLI

Add up to 1,000 people or companies to a List from Social URLs, emails, names or domains, with one result per Signal.

POST/v2/lists/:listId/members

Credits

Free to call.

Each new person costs 1 credit from a Social profile URL (2 with live), 2 from an email or a name. Each new company costs 1 credit from a company page URL or a company id (2 when the page is read live), 2 from a domain. A member already on the List, or a Signal no one matches, is free.

Introduction

The Add members endpoint turns up to 1,000 Signals into List Members and answers once they are all done. A Signal is what you know about someone: a Social profile URL, an email, or a first and last name with a company for a person; a company page URL, a domain or a company id for a company. The response holds one result per Signal, in the order you sent them, so you can match each line of your file to the member it became.

A Signal no one matches is kept on the List as Pending Intake, free. When a Signal sent again finds someone, the new member replaces its Pending Intake line. A person or company already on the List is left as it is, free, with one exception: the email of an email Signal becomes the member's work email (families.contactEmail, source: "signal:paste" or "signal:file") when the List has not found one yet, for free. This holds for a new member too, so a later email lookup never buys back an address you gave.

To add more than 1,000 Signals, to buy data families (profile, company, email, phone) for each member, to set a credit ceiling or to be told by webhook, use Import members and data instead.

Credits

The call itself is free: only the new members are charged, at the price of the Signal that found them.

SignalPeople ListCompanies List
Social URL, from saved data1 credit1 credit, 2 when the company page is read live
Social URL with live: true2 creditsAs without live: live has no effect on companies
Email, or first and last name with a company2 creditsRefused
Company id (com_...)Refused1 credit, 2 when the company page is read live
Domain aloneRefused2 credits
Already on the List, or matched by no oneFreeFree

A Signal of the other kind (a company on a people List, a person on a companies List) refuses the request with 400 LIST_ENTITY_MISMATCH. Before anything is added, the API checks that your balance covers what the batch could charge: every Signal at its price, except a Social URL already on the List or repeated in the batch (an email, a name, a domain or a company id is always counted, and a company page URL or id at 1 credit). Below that, the request returns 402 and nothing is charged. Each new member is then charged before it is written. A person or company that asked us to stop processing their data is refused (data_subject_blocked): nothing is kept or charged for it. data.creditsConsumed and quotas.creditsConsumed both give what the call charged.

The API key needs the lists permission, plus persons:enrich for a people List or companies:enrich for a companies List (see API key management).

Authorization

NameTypeRequiredDescription
apikeystringYesYour API key from the developer dashboard. Pass it via Authorization: Bearer YOUR_API_KEY header.

Request body

The List is named in the path: POST /v2/lists/:listId/members.

NameTypeRequiredDescription
signalsarrayYes1 to 1,000 Signals, described below
livebooleanNotrue fetches the profile of a Social profile URL live (2 credits). Omitted or false, saved data is used (1 credit). No effect on a companies List.
sourcestringNopaste (default) or file: how a Pending Intake line says it arrived

Each Signal is an object with the fields that identify one person or one company:

FieldTypeDescription
linkedinUrlstringProfile URL (people List) or company page URL (companies List). url is accepted as an alias.
emailstringEmail of the person
firstNamestringFirst name, with lastName and companyDomain or companyName
lastNamestringLast name, with firstName and companyDomain or companyName
companyDomainstringFor a person, the domain of their company. On a companies List, the company itself.
companyNamestringCompany name, a hint for a person found by name
domainstringCompany domain, on a companies List
companyIdstringCompany id (com_...) returned by our API, on a companies List
externalIdstringYour own identifier for the line, 1 to 200 characters. It is echoed in the line result and kept on the member, so List members can find it. A member keeps the first one it receives. It is never used to find anyone.

One invalid Signal refuses the whole request before anything is charged, and error.details.signalIndex gives its position.

Response structure

The request answers once every Signal has been handled. It runs within a 62-second time limit: past it, it returns 504, and the members already added stay added and charged. Read the List to see where it stopped, or send large batches through the import.

FieldTypeDescription
successbooleantrue if the request was processed
errornullAlways null on success
dataobject

What became of the Signals

Show child attributes
FieldTypeDescription
insertednumberMembers added
skippednumberSignals naming a member already on the List
refusednumberSignals refused for the member limit, an ambiguous identity or data_subject_blocked. A line stopped by credits or by the Pending Intake limit reads refused in results but is not counted here.
unresolvedCountnumberSignals no one matched, kept as Pending Intake
creditsConsumednumberCredits charged by this call
stoppedReasonstringPresent when a stop left later Signals unread: quota (credits), member_cap or pending_cap (List limits)
resultsobject[]

One entry per Signal, in request order

Show child attributes
FieldTypeDescription
indexnumberPosition of the Signal in the request, from 0
outcomestringadded, already_present, not_found, refused, failed or not_reached
externalIdstringYour identifier, as sent
memberIdstringThe member the line names, for added and already_present
entityIdstringPerson (prs_...) or company (com_...) id
pendingIdstringThe Pending Intake line kept for a not_found Signal
reasonstringWhy a line was refused, failed or not reached: member_limit, pending_intake_limit, insufficient_credits, ambiguous_identity, data_subject_blocked, identity_unavailable, quota_unavailable or stopped

quotas and metadata are the blocks of every V2 response: see Usage.

Errors

StatusCodeMeaning
400LIST_INVALID_INPUTA Signal cannot identify anyone, see error.details.signalIndex
400LIST_ENTITY_MISMATCHA Signal names a company on a people List, or a person on a companies List
402INSUFFICIENT_CREDITSThe balance cannot pay for what the batch could charge
403INSUFFICIENT_PERMISSIONSThe key lacks lists, or the enrich permission of the List's entity
404LIST_NOT_FOUNDNo List with this id in your workspace
404LISTS_NOT_ACTIVATEDThe workspace has never had a List: create one first
409LIST_MEMBER_LIMIT_REACHEDA request with a single Signal, on a List that already holds 25,000 members (50 on the free trial)
409LIST_PENDING_INTAKE_LIMIT_REACHEDA request with a single Signal no one matches, on a List that already holds 25,000 Pending Intake lines (50 on the free trial)
504GATEWAY_TIMEOUTThe request ran out of time after 62 seconds: the Signals already added stay added

With several Signals, a full List does not refuse the request: it answers 200, the line that met the limit reads refused (member_limit or pending_intake_limit), the next ones read not_reached, and stoppedReason is member_cap or pending_cap.

Code examples

Code Examples

curl -X POST https://api.reversecontact.com/v2/lists/3f6c2a8e-1b4d-4f0a-9c7e-5d2b8a1e6f40/members \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "signals": [
      { "linkedinUrl": "https://www.social.com/in/janedoe", "externalId": "crm-001" },
      { "email": "john.smith@acme.com", "externalId": "crm-002" },
      { "firstName": "Ana", "lastName": "Lopez", "companyDomain": "northwind.com", "externalId": "crm-003" }
    ]
  }'

Example response

In this example, the Social profile URL adds a new member (1 credit), the email names a person already on the List (free), and no one matches the name (free, kept as Pending Intake).

200 - Success

Example Response

{
  "success": true,
  "data": {
    "inserted": 1,
    "skipped": 1,
    "refused": 0,
    "unresolvedCount": 1,
    "creditsConsumed": 1,
    "results": [
      {
        "index": 0,
        "outcome": "added",
        "externalId": "crm-001",
        "memberId": "9b1e4c7a-2d3f-4e8a-b6c5-0a1f2e3d4c5b",
        "entityId": "prs_01jbd5vewyenebxgaz869ffe5t"
      },
      {
        "index": 1,
        "outcome": "already_present",
        "externalId": "crm-002",
        "memberId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "entityId": "prs_01h2x3y4z5a6b7c8d9e0f1g2h3"
      },
      {
        "index": 2,
        "outcome": "not_found",
        "externalId": "crm-003",
        "pendingId": "7e8f9a0b-1c2d-4e3f-8a4b-5c6d7e8f9a0b"
      }
    ]
  },
  "error": null,
  "quotas": {
    "creditsConsumed": 1,
    "workspace": {
      "id": "ws_abc123",
      "credits": { "total": 10000, "used": 4522, "left": 5478 }
    }
  },
  "metadata": {
    "requestId": "req_a1d2d3m4e5m6",
    "executionTimeMs": 2140
  }
}