FairValid

Developer reference · v1

Customer API

Submit a verification job, read results, and receive a signed completion event.

Get started

Create a Test key in API keys, keep it on your server, and set FAIRVALID_API_KEY and FAIRVALID_BASE_URL. Test keys work with reserved @example.com addresses. They make no provider call and use no credits.

curl -X POST "$FAIRVALID_BASE_URL/api/v1/jobs" \
  -H "Authorization: Bearer $FAIRVALID_API_KEY" \
  -H "Idempotency-Key: my-import-2026-10-05" \
  -H "Content-Type: application/json" \
  -d '{"emails":["deliverable@example.com","pending@example.com"]}'

A new job returns HTTP 202 and a UUID job_id. A matching retry returns HTTP 200 with the same job. Responses include version: v1, brand: FairValid, and no-store headers.

Keys and spending caps

Pass Authorization: Bearer fv_live_… or Bearer fv_test_… from a server. Full secrets appear only once. Live keys can have submit, read, and balance scopes. A revoked key stops new requests. Test keys access their own simulated jobs.

A live key's lifetime cap counts credits already charged plus credits reserved for accepted unique identities. It cannot add credits to the workspace. A new request over the cap returns HTTP 402 key_cap_reached without creating a job or hold. Lowering the cap blocks new work; accepted work continues.

Live verification currently depends on closed admission and proof gates. While closed, a live submit returns HTTP 503 live_verification_unavailable and holds no credits. Test mode remains available.

Jobs and results

MethodPathPurpose
POST/api/v1/jobsSubmit 1 to 5,000 addresses in JSON, up to 2 MiB.
POST/api/v1/verificationsSubmit one live address or use the original single-address simulator.
GET/api/v1/jobs/{id}Read the current job state and summary.
GET/api/v1/jobs/{id}/resultsRead up to 50 results and a signed next cursor.
POST/api/v1/jobs/{id}/cancelRequest cancellation; in-flight work may finish.
GET/api/v1/balanceRead live workspace available and held credits.
curl "$FAIRVALID_BASE_URL/api/v1/jobs/$JOB_ID" \
  -H "Authorization: Bearer $FAIRVALID_API_KEY"
curl "$FAIRVALID_BASE_URL/api/v1/jobs/$JOB_ID/results" \
  -H "Authorization: Bearer $FAIRVALID_API_KEY"

Pass next_cursor as the cursor query parameter. It carries the original filter and search. Filters are all, valid, invalid, catch_all, unknown, still_checking, and not_checked. Live result and credit states match the dashboard snapshot. Job status can be queued, running, paused, canceling, canceled, or completed. Test jobs return deterministic completed, pending, failed, or cancelled states.

Errors and safe retries

Send an Idempotency-Key of 8 to 128 allowed letters, digits, dots, colons, underscores or hyphens on every job submission and live single-address submission. Retry an uncertain response with the same key and the same normalized body. Reusing the key with a changed body returns HTTP 409 idempotency_conflict. Use a new key only when you intend a fresh, potentially charged run.

HTTP 401 means the key is missing, revoked or lacks scope. HTTP 422 covers invalid addresses or list limits. Test bulk jobs return HTTP 429 after 20 new jobs per workspace per hour or 100 per 30 days; identical retries still return the original job. HTTP 503 means the request is temporarily unavailable; a 503 after an uncertain submission does not establish that a job was absent, so retry with the same idempotency key. Errors contain a code, message and request ID.

Free sandbox

Test keys accept only these addresses: deliverable@example.com, undeliverable@example.com, risky@example.com, unknown@example.com, pending@example.com, and error@example.com. They simulate valid, invalid, catch-all, unknown, pending and unavailable outcomes. Bulk test jobs support status, results, cancellation and replay without touching the live verification or credit ledger.

Bulk sandbox jobs and their replay records are retained for 30 days. After that window, use a new idempotency key for a new test.

The original /api/v1/verifications test-key simulator uses its earlier 2026-10-01 response version and camelCase fields. Use /api/v1/jobs for the versioned bulk simulator.

Signed webhooks

Owner and Manager roles configure HTTPS endpoints for job.completed and job.canceled. A test ping uses test.ping. Job payloads contain a stable event ID, job ID, state, address-free summary, charged/returned counts and a results URL. They never include email addresses or provider data.

Read FairValid-Webhook-Id, FairValid-Webhook-Timestamp, and FairValid-Webhook-Signature. The signature is fv1= followed by lowercase HMAC-SHA256 hex over the raw bytes of fv1\n{event ID}\n{Unix timestamp}\nfollowed immediately by the raw JSON body. Use a constant-time comparison. Reject timestamps over five minutes from your clock and deduplicate by event ID in durable storage.

Return any 2xx within 10 seconds. Failed or uncertain deliveries retry up to eight times with the same event ID; inspect 30-day history or redeliver manually. Redirects and private destinations are refused. New attempts use the new secret after rotation. Keep the previous secret for 24 hours to verify signatures from in-flight attempts.

Runnable examples

The repository includes packages/contracts/examples/job.mjsand packages/contracts/examples/webhook-receiver.mjs. Run the job example with Node 22 and a Test key. The receiver verifies exact raw body bytes and both current and previous secrets during rotation. Put HTTPS in front of it and replace its in-memory event-ID set with a durable atomic store before production use.

FAIRVALID_API_KEY=... FAIRVALID_BASE_URL=https://YOUR_FAIRVALID_HOST \
  node packages/contracts/examples/job.mjs