Skip to content

Bulk jobs

Upload a CSV in the dashboard under Bulk, or send a list to the API. Jobs run in the background; a 100,000-row list usually takes a few minutes.

  • One check type per job: email, phone, phone_type, ip, domain_age, or email_auth.
  • Duplicates and blank rows are free. Inputs are folded before checking (emails and domains case-insensitively, phones by their digits).
  • Credits are the same as single lookups: 1 per unique input, with the usual free answers, and anything you checked in the last 7 days is a free repeat.
  • Credits are reserved when the job starts: one per unique input (the worst case). If you don’t have enough, nothing starts (402 INSUFFICIENT_CREDITS). Because they’re set aside, a job can’t run out partway through, even with lookups or other jobs running at the same time. Free answers and repeats are handed back when the job finishes or is stopped.
  • If something fails partway: a row whose data source didn’t answer isn’t charged and is marked as an error; the job carries on. Re-run just those rows with Re-run failed rows (or POST /v1/bulk/jobs/{id}/retry). Invalid inputs aren’t retried. If part of a job stalls, it’s retried automatically; after three tries the rows left are marked NOT_CHECKED (free, re-runnable) and the job finishes.
  • Low-credit emails, credits.low / credits.depleted webhooks, and automatic top-ups wait while a bulk job holds credits, and are checked against your real balance once the last job finishes, so a reservation never triggers them by itself.
  • When it’s done you get an email (jobs started in the dashboard) and a bulk.completed webhook.
  • Results and files are deleted 7 days after the job starts.

Choose a CSV (up to 20 MB) or paste one value per line. We guess the column and check type from the header; change them if needed, and see how many credits it uses before you start. When it finishes, the Download panel lets you choose:

  • Rows: any of approve, verify, review, block, couldn’t check, skipped (or all). Approve only gives a ready-to-use clean list.
  • Result columns: basic (vc_action, vc_status, vc_reason, vc_risk_score), everything (including details like vc_smtp_check or vc_line_type), or pick your own.
  • Keep my file’s columns: your original rows and columns with the result columns added (duplicates get their input’s result), or just input plus results.
  • Format: CSV, or JSON Lines (one JSON object per line).
Terminal window
curl https://api.validationcheck.net/v1/bulk/jobs \
-H "Authorization: Bearer $VC_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "email", "name": "March leads", "inputs": ["jane@example.com", "john@example.org"]}'

The response (202) is the job: id, status, unique_inputs, processed, credits_used, counts by recommendation, and expires_at. Then:

GET /v1/bulk/jobs/{id} Progress and counts
GET /v1/bulk/jobs/{id}/results?limit=1000&cursor=…&action=approve Results as JSON, one per unique input; pass next_cursor back as cursor
GET /v1/bulk/jobs/{id}/results.csv?results=approve,review&fields=basic&original=0&format=jsonl Results as a file, with the same choices as the dashboard (all optional)
POST /v1/bulk/jobs/{id}/retry New job with the rows that failed for temporary reasons
DELETE /v1/bulk/jobs/{id} Stop the job; unchecked inputs aren’t charged
GET /v1/bulk/jobs Your last 50 jobs

Instead of polling, subscribe a webhook to bulk.completed. Options: country (default for phones without a +), smtp: false (emails: skip mailbox checks). Requests can be up to 10 MB and 100,000 inputs. The key needs the bulk scope (on by default) and the scope for the check type.