API Documentation

VerifiedFast provides a unified REST API for verifying professional licenses and registrations across 15 professions. One endpoint, one API key, one response format. New verifications run asynchronously with a polling model for reliable results.

Base URL: https://api.verified.fast/v1

Authentication

All API requests require authentication via a Bearer token in the Authorization header.

Authorization: Bearer rk_your_api_key

You can also use the X-API-Key header as an alternative.

API keys follow the format rk_<random>. Get your key from the pricing page.

Verify Endpoint

GET/v1/verify

Async by default: For new (non-cached) verifications, this endpoint returns 202 Accepted with a job_id. Poll the status endpoint to get the final result. Cached results still return 200 instantly.

Parameters

ParamRequiredDescription
typeNoProfession type. Default: lawyer. See all 15 types below.
nameYesFull professional name (or entity name for company/facility)
stateVaries2-letter state code. Required for most types, optional for pilot.
license_numberNoLicense, registration, or certificate number for exact matching
bar_numberNoBar number (lawyer type only)
npiNoNPI number (doctor type only)
cityNoCity for disambiguation
organizationNoEmployer or practice name for disambiguation
firmNoFirm name (lawyer type only)
attorney_idNoInternal attorney ID (lawyer type only, alternative to name)
forceNoSet to 1 to bypass the 90-day cache

Async Polling

New verifications (cache misses) are processed asynchronously. The API immediately returns a 202 with a job ID. Poll the status endpoint every 15-20 seconds until the result is ready.

Flow

1. Request
2. Get job_id (202)
3. Poll status
4. Get result (200)
GET/v1/verify/status/{jobId}

Status Endpoint

Poll this endpoint with the job_id from the initial 202 response.

StatusHTTP CodeResponse
processing200Job still running. Keep polling.
complete200Verification data included in response.
failed500Error details included.
Initial Response (202 Accepted)
{
  "status": "processing",
  "job_id": "cm4x7abc123def456",
  "poll_url": "/v1/verify/status/cm4x7abc123def456",
  "message": "Verification in progress. Poll the poll_url for results."
}
Completed Response (from status endpoint)
{
  "status": "complete",
  "job_id": "cm4x7abc123def456",
  "elapsed_ms": 18430,
  "source": "live",
  "type": "doctor",
  "data": {
    "verified": true,
    "match_confidence": 0.94,
    "full_name": "Dr. Sarah Johnson",
    "license_status": "Active",
    ...
  }
}

Profession Types

Pass one of these values as the type parameter.

Type ValueProfessionExtra ParamsSources
lawyerLawyerbar_number, firmstate bar directory, state disciplinary commission, court attorney roll
doctorPhysiciannpi, license_numberNPI registry, state medical board, hospital profiles, physician directories
nurseNurselicense_numberstate nursing board, Nursys verification
dentistDentistlicense_numberstate dental board, dental licensing authority
pharmacistPharmacistlicense_numberstate pharmacy board, pharmacy licensing authority
architectArchitectlicense_numberstate architecture board, NCARB registry
engineerEngineerlicense_numberstate engineering board, NCEES verification
contractorContractorlicense_numberstate contractor licensing board, construction licensing authority
real-estateReal Estate Agentlicense_numberstate real estate commission, real estate licensing board
insuranceInsurance Agentlicense_numberstate insurance department, insurance licensing authority
financial-advisorFinancial Advisorlicense_numberFINRA BrokerCheck, SEC adviser database
lobbyistLobbyistlicense_numberstate lobbyist registry, federal lobbying disclosure database
pilotPilotlicense_numberFAA airman registry
companyBusiness Entitylicense_numbersecretary of state registry
healthcare-facilityHealthcare Facilitylicense_numberstate health department, CMS registry

Response Format

The API returns different responses depending on whether the result is cached or requires a new verification.

Cache Hit

200 + data

New Verification

202 + job_id

Job Complete

200 + data

Verification Data Fields
status
string

"complete", "processing", or "failed"

source
string

"cache" or "live"

job_id
string

Job ID (only on 202 and status responses)

type
string

Profession type that was verified

data.verified
boolean

Whether the professional was confirmed

data.match_confidence
float

0.0 to 1.0 confidence score

data.full_name
string

Verified full name

data.profession
string

Profession type

data.license_number
string

License or registration number

data.license_status
string

Active, Inactive, Suspended, etc.

data.issuing_authority
string

Board or agency name

data.disciplinary_actions
array

Disciplinary actions on record

data.organization
string

Employer or practice name

data.city
string

City

data.state
string

State

data.sources
array

URLs of sources consulted

Cache Hit (200 — instant)
{
  "source": "cache",
  "type": "doctor",
  "data": {
    "verified": true,
    "match_confidence": 0.94,
    "full_name": "Dr. Sarah Johnson",
    "license_status": "Active",
    "license_number": "MD-2019-43521",
    "issuing_authority": "Illinois Medical Board",
    ...
  }
}
New Verification (202 — poll for result)
{
  "status": "processing",
  "job_id": "cm4x7abc123def456",
  "poll_url": "/v1/verify/status/cm4x7abc123def456",
  "message": "Verification in progress. Poll the poll_url for results."
}

Lawyer type note: When type=lawyer (default), the response uses the legacy attorney schema with fields like bar_number, bar_status, bar_admissions, law_school, etc. for backward compatibility.

ID Verification (Hosted Link)

Create a secure hosted link for identity verification. The subject uploads a government-issued ID and selfie. gpt-5.6-luna vision analysis performs face matching and OCR extraction. Each completed verification costs 3 credits.

Flow: Create session (POST) → Send hosted URL to user → User uploads ID + selfie → Retrieve result (GET) or receive webhook callback.

POST/api/verified/id-verify3 credits

Create Verification Session

Creates a new ID verification session and returns a hosted URL to send to the person being verified.

Body ParamRequiredDescription
reference_idNoYour internal reference (e.g. user ID, order ID)
callback_urlNoWebhook URL — receives POST when verification completes
expires_inNoSession expiry in seconds (default: 86400 = 24h, max: 604800 = 7d)
Request
curl -X POST \
  -H "Authorization: Bearer vf_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "user-123",
    "callback_url": "https://example.com/webhook",
    "expires_in": 3600
  }' \
  https://verified.fast/api/verified/id-verify
Response (201 Created)
{
  "session_id": "a1b2c3d4-e5f6-...",
  "verify_url": "https://verified.fast/verify/a1b2c3d4-e5f6-...",
  "expires_at": "2026-03-04T16:00:00.000Z",
  "status": "pending",
  "reference_id": "user-123"
}
GET/api/verified/id-verify/{sessionId}

Retrieve Verification Result

Returns the current status and results of a verification session. Only the API key that created the session can retrieve it.

Session Statuses

StatusDescription
pendingWaiting for user to upload ID and selfie
processingImages received, vision analysis in progress
completedVerification finished — results available
expiredSession expired before user completed verification
failedAnalysis failed (e.g. unreadable ID)
Response (completed)
{
  "session_id": "a1b2c3d4-e5f6-...",
  "status": "completed",
  "reference_id": "user-123",
  "face_match": true,
  "face_confidence": 0.95,
  "id_type": "drivers_license",
  "id_data": {
    "full_name": "John Michael Smith",
    "date_of_birth": "1985-03-15",
    "address": "123 Main St, Springfield, IL 62701",
    "id_number": "S123-4567-8901",
    "expiry_date": "2028-06-01",
    "issuing_state": "IL",
    "issuing_country": "US",
    "is_valid_id": true,
    "flags": []
  },
  "completed_at": "2026-03-04T15:30:00Z",
  "created_at": "2026-03-04T15:25:00Z"
}
GET/api/verified/id-verify

List Sessions

Returns your recent verification sessions. Supports filtering by status and pagination.

Query ParamDescription
statusFilter by status (pending, completed, expired, etc.)
limitNumber of results (default 20, max 100)
offsetPagination offset
DELETE/api/verified/id-verify/{sessionId}

Cancel Session

Cancel a pending verification session. Only works on sessions with status "pending". No credits are charged for cancelled sessions.

Webhook Callback

If you provide a callback_url when creating a session, we'll POST the result to that URL when the verification completes.

Webhook Payload
{
  "event": "id_verification.completed",
  "session_id": "a1b2c3d4-e5f6-...",
  "face_match": true,
  "face_confidence": 0.95,
  "id_type": "drivers_license",
  "id_data": {
    "full_name": "John Michael Smith",
    "date_of_birth": "1985-03-15",
    "address": "123 Main St, Springfield, IL 62701",
    "id_number": "S123-4567-8901",
    "expiry_date": "2028-06-01",
    "issuing_state": "IL"
  },
  "completed_at": "2026-03-04T15:30:00Z"
}

Integration Examples

Python — ID Verification
import requests

API = "https://verified.fast/api/verified"
HEADERS = {"Authorization": "Bearer vf_your_key"}

# Create session
session = requests.post(f"{API}/id-verify",
    headers=HEADERS,
    json={
        "reference_id": "user-123",
        "callback_url": "https://example.com/hook"
    }
).json()

print(f"Send this link: {session['verify_url']}")

# Later: check result
result = requests.get(
    f"{API}/id-verify/{session['session_id']}",
    headers=HEADERS
).json()

if result["status"] == "completed":
    print(f"Match: {result['face_match']}")
    print(f"Name: {result['id_data']['full_name']}")
JavaScript — ID Verification
const API = "https://verified.fast/api/verified";
const headers = {
  "Authorization": "Bearer vf_your_key",
  "Content-Type": "application/json"
};

// Create session
const session = await fetch(`${API}/id-verify`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    reference_id: "user-123",
    callback_url: "https://example.com/hook"
  })
}).then(r => r.json());

console.log("Send link:", session.verify_url);

// Later: check result
const result = await fetch(
  `${API}/id-verify/${session.session_id}`,
  { headers }
).then(r => r.json());

if (result.status === "completed") {
  console.log("Match:", result.face_match);
  console.log("Name:", result.id_data.full_name);
}

SMS Phone Verification

Verify phone numbers by sending a 6-digit OTP code via SMS. The user enters the code in your application and you confirm it through the API. Each successful verification costs 10 credits.

Flow: Send code (POST /v1/sms/send) → User receives SMS → Verify code (POST /v1/sms/verify/{session_id}) → Credits deducted on success.

POST/v1/sms/send

Send Verification Code

Sends a 6-digit verification code to the specified phone number via SMS from (888) 374-3977.

Body ParamRequiredDescription
phoneYesUS phone number (any format: 555-123-4567, (555) 123-4567, +15551234567)
reference_idNoYour internal reference for this verification (e.g. user ID)
expires_inNoCode expiry in seconds (default: 600 = 10min, max: 1800 = 30min)
Request
curl -X POST \
  -H "Authorization: Bearer rk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"phone": "(555) 123-4567", "reference_id": "user-456"}' \
  https://api.verified.fast/v1/sms/send
Response (201 Created)
{
  "session_id": "a1b2c3d4-e5f6-...",
  "phone": "+1***4567",
  "expires_at": "2026-03-04T12:10:00Z",
  "status": "pending",
  "reference_id": "user-456"
}
POST/v1/sms/verify/{session_id}10 credits

Verify Code

Submit the 6-digit code entered by the user. 10 credits are deducted on successful verification only.

Body ParamRequiredDescription
codeYesThe 6-digit code from the SMS
Request
curl -X POST \
  -H "Authorization: Bearer rk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"code": "482916"}' \
  https://api.verified.fast/v1/sms/verify/a1b2c3d4-e5f6-...
Response (200 — Verified)
{
  "verified": true,
  "session_id": "a1b2c3d4-e5f6-...",
  "phone": "+1***4567",
  "reference_id": "user-456",
  "verified_at": "2026-03-04T12:03:42Z"
}
Response (400 — Wrong Code)
{
  "verified": false,
  "error": "Invalid code",
  "attempts_remaining": 3
}
POST/v1/sms/verify/{session_id}/resend

Resend Code

Generates a new 6-digit code and sends it to the same phone number. Resets the attempt counter. Maximum 3 resends per session.

Response
{
  "session_id": "a1b2c3d4-e5f6-...",
  "resent": true,
  "resend_count": 1,
  "max_resends": 3
}
GET/v1/sms/verify/{session_id}

Check Status

Returns current session status, attempt count, and timestamps without submitting a code.

DELETE/v1/sms/verify/{session_id}

Cancel Session

Cancel a pending SMS verification session. No credits are charged.

Session Statuses

StatusDescription
pendingCode sent, waiting for user to submit it
verifiedCode matched — phone verified (10 credits deducted)
expiredSession expired before code was submitted
failedMaximum attempts exceeded (5 wrong codes)
cancelledSession cancelled via DELETE

Security

  • • OTP codes are SHA-256 hashed before storage — never stored in plaintext
  • • Maximum 5 verification attempts per session
  • • Maximum 3 code resends per session
  • • Rate limit: 10 SMS per phone number per hour
  • • Configurable expiry: 1–30 minutes (default 10 min)
  • • Phone numbers masked in API responses (+1***4567)

Integration Examples

Python — SMS Verification
import requests

API = "https://api.verified.fast/v1"
HEADERS = {"Authorization": "Bearer rk_your_key"}

# Send code
resp = requests.post(f"{API}/sms/send",
    headers=HEADERS,
    json={"phone": "555-123-4567", "reference_id": "user-456"}
).json()

session_id = resp["session_id"]
print(f"Code sent to {resp['phone']}")

# User enters code in your app...
user_code = input("Enter code: ")

# Verify
result = requests.post(
    f"{API}/sms/verify/{session_id}",
    headers=HEADERS,
    json={"code": user_code}
).json()

if result.get("verified"):
    print("Phone verified!")
else:
    print(f"Failed: {result.get('error')}")
JavaScript — SMS Verification
const API = "https://api.verified.fast/v1";
const headers = {
  "Authorization": "Bearer rk_your_key",
  "Content-Type": "application/json"
};

// Send code
const { session_id, phone } = await fetch(
  `${API}/sms/send`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      phone: "555-123-4567",
      reference_id: "user-456"
    })
  }
).then(r => r.json());

console.log(`Code sent to ${phone}`);

// After user enters code in your UI...
const result = await fetch(
  `${API}/sms/verify/${session_id}`, {
    method: "POST",
    headers,
    body: JSON.stringify({ code: userInput })
  }
).then(r => r.json());

if (result.verified) {
  console.log("Phone verified!");
}

Caching

Verification results are cached for 90 days. Cached results return instantly with a 200 status. Cache misses start an async job and return 202.

ScenarioHTTP StatusLatencyBehavior
cache hit20010-20msData returned immediately
cache miss202< 100msReturns job_id, poll for result (15-60s)

To force a fresh verification (bypass cache), pass force=1 as a query parameter.

Error Codes

StatusMeaningResponse Body
200Success (cached result or completed job){ "source": "...", "data": {...} }
202Accepted — verification started, poll for result{ "status": "processing", "job_id": "...", "poll_url": "..." }
400Bad request (missing params or invalid type){ "error": "..." }
401Unauthorized (missing or invalid API key){ "error": "..." }
402Insufficient credits{ "error": "Insufficient credits", "purchase_url": "https://verified.fast/dashboard" }
500Server error / verification failed{ "error": "...", "details": "..." }

Code Examples

cURL — Full Async Flow
# Step 1: Start a verification (returns 202 with job_id for new lookups)
curl -s -H "Authorization: Bearer rk_your_key" \
  "https://api.verified.fast/v1/verify?type=doctor&name=Sarah+Johnson&state=IL"

# Response: {"status":"processing","job_id":"cm4x7abc...","poll_url":"/v1/verify/status/cm4x7abc..."}

# Step 2: Poll for results (every 15-20 seconds)
curl -s -H "Authorization: Bearer rk_your_key" \
  "https://api.verified.fast/v1/verify/status/cm4x7abc..."

# When complete: {"status":"complete","data":{"verified":true,...}}

# Note: Cached results return 200 with data immediately (no polling needed)
Python — with polling
import requests, time

API = "https://api.verified.fast/v1"
HEADERS = {"Authorization": "Bearer rk_your_key"}

# Start verification
r = requests.get(f"{API}/verify", params={
    "type": "doctor",
    "name": "Sarah Johnson",
    "state": "IL"
}, headers=HEADERS)

result = r.json()

# If cached, data is already here
if r.status_code == 200:
    print(result["data"])
# If async, poll for result
elif r.status_code == 202:
    job_id = result["job_id"]
    for _ in range(15):
        time.sleep(20)
        r = requests.get(
            f"{API}/verify/status/{job_id}",
            headers=HEADERS
        )
        result = r.json()
        if result["status"] == "complete":
            print(result["data"])
            break
        if result["status"] == "failed":
            print("Error:", result["error"])
            break
JavaScript — with polling
const API = "https://api.verified.fast/v1";
const headers = {
  Authorization: "Bearer rk_your_key"
};

async function verify(type, name, state) {
  const url = `${API}/verify?type=${type}`
    + `&name=${encodeURIComponent(name)}`
    + `&state=${state}`;
  const res = await fetch(url, { headers });
  const json = await res.json();

  // Cached — return immediately
  if (res.status === 200) return json.data;

  // Async — poll for result
  if (res.status === 202) {
    const jobId = json.job_id;
    for (let i = 0; i < 15; i++) {
      await new Promise(r => setTimeout(r, 20000));
      const poll = await fetch(
        `${API}/verify/status/${jobId}`,
        { headers }
      );
      const status = await poll.json();
      if (status.status === "complete")
        return status.data;
      if (status.status === "failed")
        throw new Error(status.error);
    }
    throw new Error("Timed out");
  }
}

const data = await verify("doctor", "Sarah Johnson", "IL");
console.log(data.verified, data.license_status);
Go — with polling
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"
)

const apiBase = "https://api.verified.fast/v1"

func main() {
	params := url.Values{
		"type":  {"doctor"},
		"name":  {"Sarah Johnson"},
		"state": {"IL"},
	}
	req, _ := http.NewRequest("GET",
		apiBase+"/verify?"+params.Encode(), nil)
	req.Header.Set("Authorization", "Bearer rk_your_key")

	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	var initial map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&initial)

	if resp.StatusCode == 200 {
		fmt.Println("Cached:", initial["data"])
		return
	}

	// Poll for async result
	jobId := initial["job_id"].(string)
	for i := 0; i < 15; i++ {
		time.Sleep(20 * time.Second)
		req, _ := http.NewRequest("GET",
			apiBase+"/verify/status/"+jobId, nil)
		req.Header.Set("Authorization", "Bearer rk_your_key")
		resp, _ := http.DefaultClient.Do(req)
		var result map[string]interface{}
		json.NewDecoder(resp.Body).Decode(&result)
		resp.Body.Close()
		if result["status"] == "complete" {
			fmt.Println("Result:", result["data"])
			return
		}
	}
}

Credits & Pricing

VerifiedFast uses a prepaid credit system. Purchase credits from the dashboard and each API call deducts from your balance. Credits never expire.

API CallCredit CostDollar CostDescription
Verify / Lookup1$0.33License verification for any profession
ID Verification3$0.99Photo ID + selfie face match
SMS Verification10$3.30OTP code sent and verified

Credits are purchased at $0.33 each with a $100 minimum ($100 = 303 credits). When your balance reaches zero, the API returns 402 Insufficient credits. Purchase more credits instantly from the dashboard.