Migrate from Snov.io
This guide maps the Snov.io API (the v2 email finder, domain search, email verifier, LinkedIn profile, and company domain methods, and the v1 email count, profile, and balance methods) to Tomba. Snov.io API behavior checked on 2026-09-29 against the Snov.io 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.
- Snov.io's v2 methods are asynchronous: you start a task, then fetch its result with the
task_hash. Tomba returns the result in the response, so each start and result pair becomes one request. Set your HTTP client timeout to at least 180 seconds.
Endpoint mapping
Replace the host api.snov.io with api.tomba.io.
| Snov.io | Tomba | Notes |
|---|---|---|
POST /v1/oauth/access_token | No equivalent | Send the key and secret on every request. |
POST /v2/emails-by-domain-by-name/start, GET /v2/emails-by-domain-by-name/result | GET /v1/email-finder | One person per request. |
POST /v2/domain-search/start, GET /v2/domain-search/result/{task_hash} | GET /v1/domain-search | Company details are in data.organization. |
POST /v2/domain-search/prospects/start and .../prospects/search-emails/start/{prospect_hash}, with their results | GET /v1/domain-search | Returns people and their addresses in one response. |
POST /v2/domain-search/domain-emails/start, with its result | GET /v1/domain-search | |
POST /v2/domain-search/generic-contacts/start, with its result | GET /v1/domain-search with type=generic | |
POST /v2/email-verification/start, GET /v2/email-verification/result | GET /v1/email-verifier | One address per request. |
POST /v2/li-profiles-by-urls/start, with its result | GET /v1/linkedin | One profile per request. Returns the person's email address with their name and position. |
POST /v2/company-domain-by-name/start, with its result | GET /v1/domain-suggestions | One name per request. |
POST /v1/get-domain-emails-count | GET /v1/email-count | |
POST /v1/get-profile-by-email | GET /v1/enrich | |
GET /v1/get-balance | GET /v1/me | See Check usage. |
Authentication changes
Snov.io exchanges a client ID and secret for an access token that lasts one hour, then sends it as a bearer token. Tomba has no token exchange: send the key and secret as X-Tomba-Key and X-Tomba-Secret on every request.
Code
Tomba API keys expire; plan their rotation with Key expiry.
Parameter mapping
| Snov.io method and field | Tomba parameter | Notes |
|---|---|---|
Email finder rows[].first_name, rows[].last_name | first_name, last_name | Send one person per request, or use a bulk finder job for lists. |
Email finder rows[].domain | domain | Tomba also accepts a company name as company. |
Domain search domain | domain | |
Prospects positions[] | No equivalent | department filters by department from a fixed list; see the API reference. |
Prospects page | page | |
Email verifier emails[] | email | Send one address per request, or use a bulk verifier job for lists. |
LinkedIn profiles urls[] | url | |
Company domain names[] | query | |
Email count domain | domain | |
Profile by email email | email | |
webhook_url | webhook_url | Tomba still returns the result in the response, and also posts it to your URL when the result qualifies. See Per-request callbacks. |
task_hash | No equivalent |
Response field mapping
Tomba wraps every result in data.
| Snov.io | Tomba | Notes |
|---|---|---|
Result status (completed, in_progress) | No equivalent | Every Tomba response is final. |
Finder data[].people | data.full_name | |
Finder data[].result[].email | data.email | null when no address is found. |
Finder and verifier smtp_status | Finder data.verification.status; verifier data.email.status | See Status mapping. |
Verifier is_valid_format | data.email.regex | A malformed address fails with 422 params_invalid. |
Verifier is_disposable, is_webmail, is_gibberish | data.email.disposable, .webmail, .gibberish | The email finder rejects disposable and webmail domains with 400 unknown_record. |
unknown_status_reason | No equivalent | A catch-all domain gives the status accept_all. |
Domain search company_name, website, city, founded, industry, size | data.organization.organization, .website_url, .location.city, .founded, .industries, .company_size | |
Domain search hq_phone | No equivalent | GET /v1/companies/find returns data.site.phoneNumbers. |
Domain search emails_count, generic_contacts_count | data.total, data.generic_emails from GET /v1/email-count | |
Prospects first_name, last_name, position | data.emails[].first_name, .last_name, .position | |
Prospects source_page | data.emails[].sources[].uri | |
Domain emails data[].email | data.emails[].email | Each address comes with verification.status. |
LinkedIn profiles name, first_name, last_name, country | data.full_name, .first_name, .last_name, .country | data.country is a two-letter country code. |
LinkedIn profiles positions[] | data.position, data.company | The current position only. |
LinkedIn profiles industry, location, skills | No equivalent | |
Email count result | data.total | |
Profile by email name, firstName, lastName, country | data.full_name, .first_name, .last_name, .country | |
Profile by email currentJobs[] | data.position, data.company, data.website_url | |
Profile by email previousJobs[], logo, locality, lastUpdateDate | No equivalent | |
Balance data.balance | GET /v1/me | See Check usage. |
Status mapping
Snov.io smtp_status | Tomba status | Tomba result (verifier) |
|---|---|---|
valid | valid | deliverable |
not_valid | invalid | undeliverable |
unknown, with unknown_status_reason catchall | accept_all | risky |
unknown, other reasons | unknown | risky |
Reported with is_disposable: true | disposable | Empty string |
The email finder uses the same status values in data.verification.status, which is null when the address hasn't been verified. Compare status case-insensitively. Each value is defined in Status values.
Error mapping
Snov.io reports a lack of credits in the result's status field. Tomba returns an HTTP error status with an errors object:
| Snov.io | Tomba | What to do |
|---|---|---|
Result status not_enough_credits | 402 quota_exceeded | Wait for your usage window to renew or add credits. |
| Expired access token | No equivalent | Tomba has no access tokens. A key past its expiry date returns 400 api_key_expired; rotate it. |
Also handle Tomba's 400 and 401 authentication_failed for missing or wrong credentials, 422 params_invalid for bad parameters, 429 rate_limit when you exceed your plan's rate limits (see Handle 429 responses), and 451 claimed_email when the owner of an address asked Tomba to stop processing it. Error responses don't consume credits; every type is listed in Errors.
Bulk and async jobs
Replace each Snov.io start and result pair with a single Tomba request, and remove the code that stores task_hash values and polls for results. For lists, run a Tomba bulk job instead of sending batches of 10:
| Snov.io method | Tomba bulk type |
|---|---|
| Email finder rows | finder: a CSV file with name and domain columns. See Email finder. |
Email verifier emails[] | verifier: a JSON list or a CSV file. See Email verifier. |
| Domain search over many domains | search: a JSON list of domains. See Domain search. |
| LinkedIn profile URLs | linkedin: a JSON list of profile URLs. See LinkedIn finder. |
Each job is created, launched, polled, and downloaded as CSV; see Lifecycle. To be notified when a job ends, set webhook_url; see Bulk job events. A job is charged when you first download its results; see Billing.
Code example
This function replaces the emails-by-domain-by-name start and result calls. It returns the same shape as Snov.io's result data array. It needs Node.js 18 or later.
Code
Cutover checklist
- Store the Tomba key and secret as
TOMBA_API_KEYandTOMBA_SECRET_KEY, send them asX-Tomba-KeyandX-Tomba-Secret, and remove the access token exchange and refresh. - Replace each start and result pair with one
GETrequest, and deletetask_hashstorage and polling. - Send one person, address, profile, or name per request, and move large lists to bulk jobs.
- Translate
smtp_statusandunknown_status_reasonwith the status mapping, comparingstatuscase-insensitively. - Handle
402where you handlednot_enough_credits, retry429afterRetry-After, and drop addresses that return451. - Run the same sample of people and addresses through both services and compare the results before you switch production traffic.