Skip to main content

Async Validation Jobs

Use asynchronous validation jobs for larger email lists that should be processed in the background. Jobs are Product Control Plane-owned public API workflows: the API authenticates with X-API-Key, reserves credits for unique submitted emails, validates asynchronously, finalizes charges for High-Value Validations, and refunds unused reserved credits.

Temporary SMTP Retry

If a recipient has valid DNS but the first SMTP attempt returns the explicit unknown_temporary status, the job pauses durably for 15 minutes and retries that recipient. If it remains temporary, the job retries once more four hours later. These retries complete before history, billing, result files, and webhooks are finalized. Policy, provider, budget, DNS, and transport unknowns are not eligible. If the final attempt is still inconclusive, the final result remains uncharged unknown. Synchronous single and bulk validation return immediately and do not wait through this deferred retry window.

Fresh Evidence

Set "force_refresh": true on POST /v1/validate/batch to bypass the control-plane domain-cache shortcut and the engine exact-email result cache. The job stores this choice and uses it on initial and deferred attempts. Omitted and false preserve normal cache-aware execution. Non-boolean values return 400 with code: "invalid_force_refresh". Authoritative suppression and recent-delivery evidence still take priority. Provider limits and other caches remain in effect, so this option does not guarantee a fresh SMTP observation for every address. Benchmark receipts do not enable freshness automatically; request both options when needed. Normal async credit reservation/refund rules still apply. The synchronous 30-day no-recharge window does not apply to async jobs. This option is for the JSON batch endpoint, not the signed CSV upload workflow.

Endpoints

Required Scope

Scoped API keys need email:validate:bulk. Legacy unrestricted keys retain compatible access until rotated.

Create Job

Use this JSON endpoint for scripts and SDKs that already have an array of emails. It accepts up to 500,000 submitted emails; valid duplicates are deduplicated before credit reservation. Each array member must be a string. Strings that fail the supported email syntax contract are skipped before credit reservation and reported in the creation response as invalid_count; valid unique strings are reported as email_count and queued for validation.
cURL
Idempotency-Key is optional and retained for 24 hours. Reuse the same opaque, non-secret key when retrying the same logical job: the API returns the original job response without creating another job or reserving credits again. Reusing a key with different emails, webhook configuration, freshness, or benchmark-receipt mode returns 409. An in-progress duplicate also returns 409 with Retry-After: 2. For prospective accuracy acquisition, add X-GTM-Benchmark-Receipt: email-benchmark-receipt-v6 and set force_refresh to true. Version 6 signs that fresh evidence was requested, along with exact mailbox identity, the bounded provider family, and the decisive reviewed Microsoft SMTP route pattern and provenance version when available. Version 5 preserves route provenance without the signed freshness claim; version 4 preserves provider-family evidence; versions 2 and 3 preserve older artifacts. Signing is preflighted before credits are reserved. When the job finishes, benchmark_receipt contains an ES256 compact JWS covering every ordered result row plus its immutable decision_id, decided_at, decision_version, and validation_source. The result CSV appends provider_family, provider_family_version, benchmark_smtp_mx_route_pattern, benchmark_smtp_provenance_version, and the three decision provenance columns. The route pair is blank when the result did not obtain decisive reviewed Microsoft SMTP evidence; do not infer it from mx_record. Receipt payloads contain digests and aggregate metadata, never raw addresses, domains, MX hosts, or verdicts. Completed job results include unknown_reason_codes, a privacy-safe count map using the same stable taxonomy as each result’s unknown_reason_code. Downloaded result CSVs include the code and validation_retry_action alongside the existing human-readable charge_reason. Retry only rows whose action is retry_later; manual_review represents structural or provider-specific uncertainty. Downloaded CSVs preserve tri-state evidence: smtp_valid and is_domain_catch_all are true or false only when that signal was measured; the cell is blank when validation did not establish the signal. A blank cell is not equivalent to false.

Signed CSV Upload

Use this flow for large CSV files so the file body goes directly to Storage instead of through the API proxy.
cURL
Upload the CSV file to the returned upload_url before the exact upload_expires_at timestamp, then start processing. CSV input must be valid UTF-8 without NUL bytes. A UTF-8 BOM is accepted; malformed UTF-8 and UTF-16 fail with an encoding-specific diagnostic before parsed-data metadata is committed.
cURL
Use a different retry key for each handshake step, such as one durable import identifier with .prepare and .start suffixes. Reusing a key with the same authenticated request returns the original successful JSON and sets Idempotency-Replayed: true; changing the filename, webhook, batch, canonical column mappings, or processing flags returns 409. An in-progress retry also returns 409 with Retry-After: 2. Prepare responses include upload_expires_at and replay only while that exact signed capability remains valid (normally two hours). After it expires, the same prepare key can create a fresh upload job, URL, and expiry. Start-processing responses remain replayable for 24 hours. These endpoint-aware windows prevent ambiguous network failures from creating duplicate jobs or queueing the same uploaded file twice. If the idempotency ledger is unavailable before the operation, the API returns 503 with code: "idempotency_unavailable"; retry the same request and key. If the upload job or queue handoff succeeded but its replay record could not be confirmed, the API returns 503 with code: "idempotency_completion_failed"; retry the same key because the side effect may already exist. Do not switch keys after an ambiguous completion. Every signed-upload error includes a stable code. For prepare-upload, repair invalid_filename, invalid_content_sha256, or invalid_webhook_url; retry upload_prepare_failed with the same key. For start-processing, repair missing_batch_id, missing_email_column, invalid_column_reference (the field property identifies the input), or incomplete_contact_columns. job_not_found means the batch is not available to this account, while invalid_job_state means it already left the upload stage. Retry processing_start_failed with the same key and bounded backoff. Column references may be a header name or a zero-based integer index. String references are trimmed, must contain a non-whitespace character, and may contain at most 255 Unicode characters including surrounding whitespace. A canonical nonnegative integer string of up to 15 digits, such as "2", is treated as index 2; use a JSON integer for larger safe indexes. Other strings, including numeric-prefix names such as 1st_email, remain literal header names. Header-name matching is case-insensitive and must identify exactly one column. If the selected name is duplicated, use its zero-based index instead; unrelated duplicate headers do not affect the job. For a missing name, a parse failure may include one high-confidence Did you mean ...? hint when there is a uniquely best nearby header. The hint is advisory: GTMAPIs never selects a fuzzy match, and ties or distant names receive no suggestion. If no delimiter can be detected and no header suggestion applies, the parse failure may conditionally recommend re-exporting a multi-column file with a comma, tab, semicolon, or pipe separator. GTMAPIs never guesses or silently changes the delimiter; valid one-column files remain supported. If you provide contact-name evidence, send both first_name_column and last_name_column; GTMAPIs uses the pair for contact-pattern evidence and rejects a missing or out-of-range explicit mapping instead of silently dropping that accuracy signal. Omit both fields when the file does not contain names. Duplicate mailbox rows are still validated and billed once. For contact-name evidence, GTMAPIs prefers a complete first/last pair from one row over partial or blank context. Equivalent pairs that differ only by case, accents, spacing, or punctuation remain usable. If complete duplicate rows identify different people, GTMAPIs suppresses name-based evidence for that mailbox rather than guessing, voting, or combining names across rows. Original CSV rows remain available in the result export.

List Jobs

cURL
Invalid filters return invalid_page, invalid_limit, or invalid_job_status. Repair the named filter before retrying.

Get Job Status

cURL
Status responses include job state, progress, summary counts, credits reserved, credits consumed, credits refunded, effective credits per High-Value Validation, and download handoff metadata without exposing internal validation batch table shape. A missing or cross-account job returns code: "job_not_found". Treat this as terminal for that ID; do not continue polling it.
deferred_smtp_retry is an aggregate-only audit of up to two delayed retries for explicit temporary SMTP unknowns, producing three total observations: the initial pass, one 15 minutes later, and a final pass four hours after that. It is omitted on older jobs. resolved means a retry produced a final non-temporary result; it does not imply the mailbox was valid or that an email was delivered. Enterprise gateways that explicitly block recipient verification remain in the combined-evidence shadow lane and are not repeatedly probed by this schedule. benchmark_receipt is present only for an opted-in API batch after the final CSV and immutable current-policy provenance are available. Verify its ES256 signature with https://api.gtmapis.com/.well-known/jwks.json, then recompute both the ordered result projection and decision-provenance digest before using the artifact for an accuracy claim.

Get Download URL

cURL
Agents and scripts should use mode=url and follow the signed URL instead of pulling raw CSV content through MCP. If results are still processing, the route returns job_not_ready and the current job status; keep polling the job detail route. job_not_found means the ID is unavailable, while job_file_not_available means the job exists but the selected stored artifact does not.

Credit Behavior

  • Credits are reserved up front for unique submitted emails.
  • Only High-Value Validations are charged when processing completes.
  • Role-based, catch-all, invalid, risky, and unknown results are refunded from the reservation.
  • Failed-job recovery should refund unused reservations idempotently.
  • Use results.high_value, results.credits_consumed, and results.credits_per_high_value_validation to measure cost per usable lead instead of raw cost per lookup.