Bulk CSV processing
tomba bulk reads a CSV file, sends one API request per row from your machine, and writes the results to a new CSV file. It doesn't use the Bulk API, so every row is billed and rate-limited as a separate request.
How it differs from the Bulk API
tomba bulk | Bulk API | |
|---|---|---|
| Where it runs | On your machine: one request per row | On Tomba's servers: one job for the whole list |
| Credits | Each row, like a single request (Credit costs); the duplicate-request rule applies to each row | Per job, when you first download the results (Billing) |
| Rate limits | Each row counts toward your rate limits | The job limits in Limits |
| Results | A CSV file written as rows complete | A CSV file you download when the job completes |
Usage
Code
The input must be a comma-separated file with a header row. Rows shorter than the header are padded, and rows whose input cell is empty are skipped without a request.
Types
--type | Calls | Input columns |
|---|---|---|
enrich (default) | GET /v1/enrich | |
verify | GET /v1/email-verifier | |
finder | GET /v1/email-finder | Domain, and first and last name or full name |
search | GET /v1/domain-search | Domain |
author | GET /v1/author-finder | Article URL |
linkedin | GET /v1/linkedin | LinkedIn profile URL |
phone | GET /v1/phone-finder | Email, domain, or LinkedIn profile URL |
phone-validator | GET /v1/phone-validator | Phone number, and optionally a country code |
company | GET /v1/companies/find | Domain |
similar | GET /v1/similar | Domain |
sources | GET /v1/email-sources |
Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--file | string | — | Input CSV file. Required. |
--type | string | enrich | Lookup to run for each row. See Types. |
--column | string | — | Email column. For phone-validator, also used as the phone column when no phone column is found. |
--domain-col | string | — | Domain column. |
--first-col | string | — | First-name column, for finder. |
--last-col | string | — | Last-name column, for finder. |
--full-name-col | string | — | Full-name column, for finder, instead of first and last name. |
--url-col | string | — | URL column, for author, linkedin, and LinkedIn URLs with phone. |
--phone-col | string | — | Phone column, for phone-validator. |
--country-code-col | string | — | Country-code column, for phone-validator. |
--enrich-mobile | bool | false | Also return phone numbers, for enrich, finder, and linkedin. Phone data changes the cost. |
--full | bool | false | Return up to 10 phone numbers per row, for phone. |
--concurrency | int | 0 | Number of parallel workers. 0 picks a number based on your plan. The maximum is 60. |
--no-resume | bool | false | Overwrite the output file and process every row. |
--output, -o | string | <input>_enriched.csv | Output file. |
The global flags --key, --secret, and --no-color also apply.
Map columns
Column names are matched without regard to case. If you don't pass a column flag, the CLI looks for these header names:
| Input | Header names |
|---|---|
email, e-mail, email_address, emailaddress, mail | |
| Domain | domain, company_domain, website, company_website |
| First name | first_name, firstname, first, fname |
| Last name | last_name, lastname, last, lname |
| Full name | full_name, fullname, full name |
| URL | url, link, linkedin, linkedin_url, article_url, profile_url |
| Phone | phone, phone_number, phonenumber, tel, telephone |
| Country code | country_code, countrycode, country |
--column sets the email column, not the domain column. For types that take a domain, pass --domain-col: with --column domain, the CLI treats that column as email addresses and asks for the domain column.
When it can't find a required column, the CLI asks you to pick one from a list. Without an interactive terminal, such as in CI, it exits with Could not find ... column; pass the column flags explicitly there.
Output file
The output has your input columns followed by the result columns for the type. search and similar write one row per address or company found, repeating the input columns; search gets the first page of results, at the API's default limit. Results are written as they arrive from the workers, so the output rows can be in a different order than the input.
When the run ends, the CLI prints a summary with the number of rows found, not found, skipped, and failed with client (4xx and network) or server (5xx) errors.
Resume a run
By default, if the output file already exists with the expected columns, the CLI skips the rows it already contains and appends the rest. A row counts as done when a row with the same input values is in the output file.
Rows that fail, for example with 429 or 402, are written with empty result columns, so a resumed run treats them as done and doesn't retry them. To retry them, delete those rows from the output file and run the command again, or rerun everything with --no-resume. The CLI doesn't retry or slow down after a 429; if the summary shows client errors, lower --concurrency and see Handle 429 responses.
If the output file exists but its columns don't match, for example because
you changed --type, the CLI starts a fresh run and overwrites the file.
The default output name doesn't include the type, so pass --output to keep
the results of each type in a separate file.
Examples
Code