Migrate from ContactOut
This guide maps the phone lookups of ContactOut's Contact Info API (single, bulk v1, and bulk v2), LinkedIn Profile API (from a LinkedIn URL and from an email address), People Enrich API, and Phone Number Checker to Tomba. ContactOut API behavior checked on 2026-09-30 against the ContactOut API reference.
Before you begin
- Get your API key (
ta_…) and secret (ts_…); see Authentication. - Check what each endpoint costs in Credit costs and your plan's throttling in Limits by plan.
- Set your HTTP client timeout to at least 180 seconds. Tomba returns the finished result in the response.
Endpoint mapping
Replace the base URL https://api.contactout.com with https://api.tomba.io.
| ContactOut | Tomba | Notes |
|---|---|---|
GET /v1/people/linkedin with include_phone=true | GET /v1/phone-finder with linkedin | For email addresses, call GET /v1/linkedin. |
GET /v1/linkedin/enrich | GET /v1/phone-finder with linkedin | Returns phone numbers only. For email addresses and profile data, call GET /v1/linkedin. |
GET /v1/email/enrich | GET /v1/enrich with enrich_mobile=true | Returns the person and their numbers in data.phone_data. For numbers only, call /v1/phone-finder with email. |
POST /v1/people/enrich with linkedin_url or email | GET /v1/phone-finder | See Parameter mapping. |
POST /v1/people/enrich with a name and company or company_domain | GET /v1/email-finder with enrich_mobile=true | Numbers are in data.phone_data. |
POST /v1/people/enrich with phone | No equivalent | Tomba doesn't look people up by phone number. GET /v1/phone-validator checks the number itself. |
GET /v1/people/linkedin/phone_status | GET /v1/linkedin, data.phone_number | true when Tomba has a number for the person. Unlike ContactOut's checker, this request can be charged; see Credit costs. |
POST /v1/people/linkedin/batch, POST /v2/people/linkedin/batch | A bulk job |
Authentication changes
ContactOut reads the key from the token header. Tomba needs two headers, X-Tomba-Key and X-Tomba-Secret:
Code
Tomba API keys expire; plan their rotation with Key expiry.
Parameter mapping
| ContactOut | Tomba | Notes |
|---|---|---|
profile, linkedin_url | linkedin | On /v1/phone-finder. On /v1/linkedin the parameter is url. |
email | email | On /v1/phone-finder or /v1/enrich. |
include_phone=true, include with phone | Not needed | /v1/phone-finder returns only phone numbers. On the finder endpoints, enrich_mobile=true adds them. |
full_name, first_name, last_name | full_name, first_name, last_name | On /v1/email-finder with enrich_mobile=true. |
company | company | On /v1/email-finder. Tomba takes one company per request; ContactOut takes an array. |
company_domain | domain | On /v1/email-finder. One domain per request. On /v1/phone-finder, domain returns the company's number. |
| No equivalent | full | full=true returns every number found as an array; without it, data holds one number, preferring a valid one. |
email_type, profile_only, phone, job_title, location, education | No equivalent |
Response field mapping
| ContactOut | Tomba | Notes |
|---|---|---|
status_code in the body | HTTP status | Tomba doesn't repeat the status in the body. |
profile.phone[] (array of numbers) | data[].e164_format with full=true | Also in intl_format, local_format, and rfc3966_format. |
profile.phone (a string, from /v1/email/enrich) | data.phone_data[].e164_format | On /v1/enrich with enrich_mobile=true. |
profile.url | data.linkedin | Only on a number found for the LinkedIn URL you sent. |
profile.email, work_email, personal_email | No equivalent on the phone finder | Call /v1/linkedin or /v1/enrich for the email address. |
profile.github, twitter, and profile details | No equivalent on the phone finder | For profile data, see the Person API. |
Phone checker profile.phone | data.phone_number on /v1/linkedin |
Tomba also returns valid, country_code, line_type, carrier, region, and timezones for each number. Every field is described in Phone response.
Status mapping
| ContactOut | Tomba |
|---|---|
404 with "message": "Not Found" | 200 with data as an empty array |
Empty phone or phones array | 200 with data as an empty array |
| No equivalent | valid is false: the number isn't valid in its country's numbering plan |
| No equivalent | line_type, such as MOBILE or FIXED_LINE; see Line types |
With full=true, filter on valid if you only want valid numbers.
Error mapping
ContactOut returns status_code and message. Tomba returns an errors object with type, message, and code:
| ContactOut | Tomba | What to do |
|---|---|---|
400 or 401 bad credentials or invalid headers | 400 authentication_failed (missing or malformed), 400 api_key_expired, 401 authentication_failed (wrong key or secret) | Check both headers; rotate an expired key. |
400 or 401 bad request or invalid input | 422 params_invalid | Fix the parameter named in the message. Sending none of email, domain, and linkedin to /v1/phone-finder also returns 422. |
403 out of credits | 402 quota_exceeded | Wait for your usage window to renew or add credits. |
404 not found | 200 with data as an empty array | Treat as no match. |
429 rate limit, with retry-after | 429 rate_limit, with Retry-After | Retry after the delay; see Handle 429 responses. |
| No equivalent | 451 claimed_email or 451 claimed_linkedin | The person asked Tomba to stop processing their data. Remove the record from your data. |
Error responses don't consume credits. Every type is listed in Errors.
Bulk and async jobs
ContactOut's bulk v1 endpoint answers up to 100 LinkedIn URLs synchronously, and bulk v2 returns a job_id to poll or a callback_url to notify. A Tomba bulk job runs in the background: create it, launch it, poll its progress, and download the results as CSV.
| ContactOut | Tomba bulk type |
|---|---|
profiles with include_phone: true | phone-finder: a JSON list or CSV file of LinkedIn URLs or email addresses. See Phone finder. |
GET /v2/people/linkedin/batch/{job_id} | Poll the job's progress, then download its results. See Lifecycle. |
callback_url | webhook_url, which receives a signed event when the job ends. See Bulk job events. |
ContactOut keys batch results by profile URL. A Tomba JSON list is de-duplicated and reordered, so join the CSV rows back to your records on the LinkedIn URL, not on position. A job is charged when you first download its results; see Billing.
Code example
This function replaces a call to GET /v1/people/linkedin with include_phone=true and returns ContactOut's profile.url and profile.phone fields, or null when no number is found. It needs Node.js 18 or later.
Code
Cutover checklist
- Store the Tomba key and secret as
TOMBA_API_KEYandTOMBA_SECRET_KEY, and send them asX-Tomba-KeyandX-Tomba-Secretinstead oftoken. - Route each lookup by its identifier: LinkedIn URL or email address to
/v1/phone-finder, name and company to/v1/email-finderwithenrich_mobile=true. Drop lookups by phone number. - Read numbers from
data(withfull=true) ordata.phone_datainstead ofprofile.phone, and use the HTTP status instead ofstatus_code. - Treat an empty
dataarray as no match, in place of404. - Swap error handling:
402replaces the out-of-credits403,422covers invalid input, and451carries aclaimed_*type. - Move batch lookups to Tomba bulk jobs and poll their progress instead of waiting for
callback_url. - Run the same sample of profiles through both services and compare the numbers before you switch production traffic.