On this page

Integration Guide

Everything you need to call the Validator REST API from your application. Three endpoints, one response envelope: each call is a base check plus the components you enable, billed per component to your prepaid wallet.

1 Prerequisites

  • A Validator account — sign up here (no subscription required).
  • An API key from your tenant portal.
  • Prepaid wallet balance for the operations you plan to run. See pricing.

2 Authentication

Pass your API key in the Authorization header as a Bearer token. There are no cookies, no sessions, and no OAuth flows for API calls.

Authorization: Bearer vlt_your_api_key_here

API keys begin with vlt_. Keep them secret — treat them like passwords.

Services catalog

Retail operations and prices come from Admin → Services. Each base check and each component you enable bills its own operation; the operations charged are returned in billing.operations.

Service Operation Price Method Path How to select
Phone check check_phone 2 credits ($0.0010) POST /v1/check/phone — (send the identifier only)
Carrier check check_phone_carrier 49 credits ($0.0245) POST /v1/check/phone `carrierCheck: true`
Ported check check_phone_ported 8 credits ($0.0040) POST /v1/check/phone `portedCheck: true`
Email check check_email 1 credit ($0.0005) POST /v1/check/email — (send the identifier only)
Email verify check_email_verify 20 credits ($0.0100) POST /v1/check/email `emailVerify: true`
Email premium check_email_premium 77 credits ($0.0385) POST /v1/check/email `emailPremium: true`
DNC screening check_phone_dnc 79 credits ($0.0395) POST /v1/check/phone `dncCheck: true`
check_phone_dnc_overlay check_phone_dnc_overlay 79 credits ($0.0395) POST /v1/check/phone `dncCheck: true`
Live line check_phone_active 28 credits ($0.0140) POST /v1/check/phone `activeCheck: true`
Caller name (CNAM) check_phone_caller_name 12 credits ($0.0060) POST /v1/check/phone `callerName: true`
Phone premium check_phone_premium 390 credits ($0.1950) POST /v1/check/phone `phonePremium: true`
Session start session_start 1 credit ($0.0005) POST /v1/sessions — (send the identifier only)
Email resend email_send 1 credit ($0.0005) POST /v1/sessions/resend `channel=email`
SMS OTP sms_otp 100 credits ($0.0500) POST /v1/sessions/resend `channel=phone`

3 Phone check

POST /v1/check/phone runs the base phone check — line type, carrier, city, state, county, ZIP, rate centre, LATA, timezone and OCN — for US and Canadian numbers. Enable any of the phone components with a boolean key to go deeper — the components you tick are the request.

Request

{
  "phone": "+18134696697",
  "dncCheck": true
}

Response (200)

{
  "ok": true,
  "phone": {
    "status": "valid",
    "confidence": 0.98,
    "e164": "+18134696697",
    "lineType": "mobile",
    "carrierName": "T-Mobile USA",
    "reference": {
      "lineType": "mobile",
      "carrierName": "T-Mobile USA",
      "ocn": "6529",
      "state": "FL",
      "city": "Tampa",
      "county": "Hillsborough",
      "zip": "33601",
      "rateCenter": "TAMPA",
      "lata": "952",
      "timezone": "America/New_York",
      "companyType": "wireless",
      "smsGateway": false
    },
    "dnc": {
      "callable": true,
      "onFederalDnc": false,
      "onStateDnc": false,
      "onLitigator": false,
      "onComplainer": false,
      "resolvedState": "FL",
      "stateDncApplicable": true,
      "recommendation": "call"
    },
    "checked": ["base", "dncCheck"],
    "source": "vendor"
  },
  "billing": {
    "charged": true,
    "operations": ["check_phone", "check_phone_dnc"],
    "totalMicroUsd": 40500,
    "totalCredits": 81
  }
}

Every endpoint returns this one envelope: ok, a phone and/or email half, and billing. Fields that were not checked are omitted — never false or null. The totals above are illustrative; read GET /v1/pricing for live prices. totalMicroUsd is the exact amount charged (1,000,000 micro = $1.00); totalCredits is the same amount in credits (1 credit = $0.0005).

Field Type Description
status string valid / invalid / risky / unknown — whether the number is usable
confidence number 0 to 1 — how sure we are of status
reason string Why the status is what it is, when there is one
e164 string Normalized E.164 number
lineType string mobile / landline / voip / tollfree / unknown
carrierName string Carrier name; normalized when carrierCheck ran
reference object Base check data: lineType, carrierName, ocn, state, city, county, zip, rateCenter, lata, timezone, companyType, smsGateway
portability object With portedCheck, carrierCheck or phonePremium: ported, portedDate, carrierChanged, carrierNative, carrierServing, provenance (npac / lrn_derived / internal / unknown)
dnc object With dncCheck or phonePremium: callable, onFederalDnc, onStateDnc, onLitigator, onComplainer, resolvedState, stateDncApplicable, recommendation, overlayUnavailable
active boolean With activeCheck or phonePremium: the line is live and assigned to a subscriber. Omitted when unknown.
callerName string With callerName or phonePremium
checked string[] Component keys that produced an answer, including base
unavailable object[] { option, reason } for each component that produced no answer. Omitted when everything ran; these are not billed.
source string vendor / cache / internal — where the answer came from

Request cadence

Each API key may send at most 2 requests per second across every /v1 endpoint. A request over that cadence returns 429 with a Retry-After header; it does not run and is not billed. Pace batches evenly instead of sending them in bursts. Identical requests sent at the same moment (same number or address, same base check and upgrades) share one lookup and receive the same answer; each completed check is billed.

4 Email check

POST /v1/check/email runs the base email check — syntax, domain, MX, disposable addresses, role addresses and blocklist signals. Enable emailVerify for mailbox-level verification or emailPremium for verification plus catch-all and abuse scoring. Both replace the base check rather than adding to it.

Request

{
  "email": "[email protected]",
  "emailVerify": true
}

Response (200)

{
  "ok": true,
  "email": {
    "status": "valid",
    "confidence": 0.97,
    "reason": "mailbox_verified",
    "hasMx": true,
    "disposable": false,
    "roleBased": false,
    "dnsblHit": false,
    "mailboxVerified": true,
    "checked": ["base", "emailVerify"],
    "source": "vendor"
  },
  "billing": {
    "charged": true,
    "operations": ["check_email_verify"],
    "totalMicroUsd": 10000,
    "totalCredits": 20
  }
}

Note the single operation in billing.operations: emailVerify replaced the base check, so the base is not billed alongside it.

Field Type Description
status string valid / invalid / risky / unknown — whether the address is usable
confidence number 0 to 1 — how sure we are of status
reason string Detail reason from the check
hasMx boolean true when MX records exist
disposable boolean true for known disposable domains
roleBased boolean true for role addresses (info@, admin@)
dnsblHit boolean true when a blocklist match was found
mailboxVerified boolean With emailVerify or emailPremium
catchAll boolean With emailPremium
abuseScore number With emailPremium
checked string[] Component keys that produced an answer, including base
unavailable object[] { option, reason } for each component that produced no answer; not billed
source string vendor / cache / internal

5 Both in one call

POST /v1/check accepts a phone, an email, or both, with any mix of phone and email components in one body. Each half is validated against its own family, runs concurrently, and is billed on its own outcome. Only the halves you supplied an identifier for appear in the response. Enabling a component for a family whose identifier is missing is a 400 — the request asked for a check that could not run.

Request

{
  "phone": "+18134696697",
  "email": "[email protected]",
  "carrierCheck": true,
  "emailPremium": true
}

Response (200)

{
  "ok": true,
  "phone": {
    "status": "valid",
    "confidence": 0.99,
    "e164": "+18134696697",
    "lineType": "mobile",
    "carrierName": "T-Mobile",
    "reference": { "…": "…" },
    "portability": {
      "ported": true,
      "portedDate": "2024-04-05",
      "carrierChanged": true,
      "carrierNative": "AERIAL COMMUNICATIONS, INC.",
      "carrierServing": "T-MOBILE USA, INC.",
      "provenance": "npac"
    },
    "checked": ["base", "carrierCheck"],
    "source": "vendor"
  },
  "email": {
    "status": "valid",
    "confidence": 0.97,
    "reason": "mailbox_verified",
    "hasMx": true,
    "disposable": false,
    "roleBased": false,
    "dnsblHit": false,
    "mailboxVerified": true,
    "catchAll": false,
    "abuseScore": 0,
    "checked": ["base", "emailPremium"],
    "source": "vendor"
  },
  "billing": {
    "charged": true,
    "operations": ["check_phone_carrier", "check_email_premium"],
    "totalMicroUsd": 79500,
    "totalCredits": 159
  }
}

When a component has no answer

HTTP stays 200 and ok stays true. The component is listed in unavailable with a reason, its fields are absent, and it is not billed. A replacement tier that cannot complete returns the base result and charges the base only — partial bundle output is never emitted.

{
  "ok": true,
  "phone": {
    "status": "valid",
    "confidence": 0.95,
    "e164": "+18134696697",
    "lineType": "mobile",
    "reference": { "…": "…" },
    "checked": ["base"],
    "unavailable": [{ "option": "activeCheck", "reason": "vendor_unavailable" }],
    "source": "internal"
  },
  "billing": {
    "charged": true,
    "operations": ["check_phone"],
    "totalMicroUsd": 1000,
    "totalCredits": 2
  }
}

6 Components

Each component is a boolean key on the request. A component adds when it is a separate lookup on top of the base check, and replaces the base when its own operation already does the base's work — so you are never charged for the same reference lookup twice. A component another selected component already includes is one check, billed once: carrierCheck covers portedCheck, phonePremium covers every phone upgrade, and emailPremium covers emailVerify.

Phone components

Key What it does Base Includes Response fields
carrierCheck Normalized carrier — A normalized name for the current serving carrier, with ported status. Replaces portedCheck carrierName, portability
portedCheck Ported check — Live line type, ported status and ported date. Replaces — portability
dncCheck DNC screening — Federal and state DNC, litigator and complainer signals. Adds to — dnc
includeTcpaScreening Modifier on dncCheck — with dncCheck, upgrades the screening to the TCPA overlay (litigator and complainer signals). Ignored on its own. Modifies — dnc
activeCheck Live line — Confirms the number is live and assigned to a subscriber — not that the handset is answering right now. Adds to — active
callerName Caller name — Caller name lookup; also included with Premium. Adds to — callerName
phonePremium Premium — Every phone upgrade: carrier, ported status, live line, DNC, TCPA and caller name. Replaces carrierCheck, portedCheck, dncCheck, activeCheck, callerName carrierName, portability, active, dnc, callerName

Email components

Key What it does Base Includes Response fields
emailVerify Verify — Mailbox-level verification. Replaces — mailboxVerified
emailPremium Premium — Mailbox verification, deliverability, catch-all and abuse scoring. Replaces emailVerify mailboxVerified, catchAll, abuseScore

Prices per component are on the pricing page and in GET /v1/pricing. The price calculator (or the API call builder in your portal once you are signed in) shows the exact request and response for any selection.

7 Error codes

HTTP Meaning Action
400 Bad request — no identifier, a component enabled for a family whose identifier is missing ({ error, missing, options }), or an unknown option ({ error, phoneOptions, emailOptions }) Fix the request body and retry
401 Unauthorized — bad or missing Bearer token Check your API key and Authorization header
402 Not enough credits in the wallet for the whole selection — checked before any lookup runs Top up your wallet via the portal
403 Forbidden — the account is suspended, or test: true was sent and test mode is not enabled for the account. Nothing ran. Contact support, or ask for test mode
429 Too many requests — the daily test-mode limit was reached. Nothing ran. Retry tomorrow (UTC), or send a live check
500 A half failed before it could answer. Nothing was charged — debits happen only after every half has answered. Retry; contact support if it persists
503 Unavailable — a component we sell cannot be served right now ({ error, unavailable: [...] }). The request is correct; nothing ran and nothing is charged. Retry with exponential back-off, or drop the named component
504 A half did not finish within the vendor budget. Nothing was charged. Retry later

All error responses are { "ok": false, "error": "…" } with a human-readable description, plus the fields named above where they apply. A conclusive "status": "invalid" is a successful check (HTTP 200, ok: true), not an error.

8 Billing

Each check is billed to your prepaid wallet per component, using the operations in the services catalog. A completed check is billed in full, whether the answer is valid or invalid — you asked whether the identifier is usable and got a correct answer. Requests rejected before any work (400, 401, 402, 403, 429, 503) and checks that failed or timed out before answering (500, 504) are not charged.

The cache and our internal checks run before any vendor is called. An answer settled there is still a completed check and bills the same operation; the source field on each half reports where the answer came from — vendor, cache or internal — and confidence (0 to 1) says how sure we are.

A component that produced no answer is listed in unavailable and is not billed. A replacement tier that cannot complete returns the base result and charges the base only. Exactly what was charged is always in billing.operations, billing.totalMicroUsd and billing.totalCredits; current rates are on the pricing page and in GET /v1/pricing.

Wallet top-up: Use the portal to add credits. Your balance is visible on the portal dashboard.

Credits: wallet balances and prices are shown in credits: 1 credit = $0.0005 (2,000 credits = $1), so a $25 top-up adds 50,000 credits. You pay top-ups in US dollars. Catalog prices are whole credits; custom pricing can carry up to three decimals.

totalMicroUsd and each price's microUsd stay the exact integers to reconcile against; totalCredits and credits are the same amounts in credits. GET /v1/pricing publishes the rate as creditsPerUsd and creditMicroUsd.

Integration test mode

Send "test": true (or dry_run) on any tenant API call or LeadConnector workflow/embed run to check that auth, routing, and the integration are wired — without live lookups, wallet charges, or CRM tag writes.

An operator must enable test mode on your account first. You get 3 test calls per UTC day. Over that limit the API returns HTTP 429. If test mode is off, the API returns HTTP 403 and does not run a live (paid) check.

Responses use the same envelope — a synthetic phone and/or email half carrying test: true. They are not real deliverability or carrier results, and the billing block reports charged: false with no operations, because nothing was charged. A valid API key (or workflow secret + connected location) is still required.

POST /v1/check/phone
Authorization: Bearer <api_key>
{
  "phone": "+18134696697",
  "test": true
}

Verification sessions

Use the sessions API when you need magic-link or OTP email verification plus optional SMS phone confirmation. Magic links point at your app_base_url — not the validator host.

  • POST /v1/sessions — start session; sends initial email
  • GET /v1/sessions/status?token=… — poll progress
  • POST /v1/sessions/confirm-email — confirm magic link or email OTP
  • POST /v1/sessions/resend — resend email or request phone SMS
  • POST /v1/sessions/verify-phone — confirm SMS OTP

Caller name lookup is not a session call — enable the callerName component on POST /v1/check/phone.

See the full flow in this guide and the OpenAPI spec.