Verify Ref Logo

VerifyRef API · v2025-05-19

Replace phone-tag reference checks with one API call.

Trigger consent emails, collect reference responses, run AI sentiment and red-flag analysis, and get a signed PDF report — all from a single REST call. No subscription lock-in: pay per check, credits never expire.

Prefer a no-code ATS hookup? Sign up, then open Dashboard → ATS integrations to connect Bullhorn, Zoho, SAP, Greenhouse, or Lever via Merge. (Coming soon)

Why teams switch to VerifyRef

  • One API call replaces manual chasing — consent, reminders, and collection are automated
  • ~95% reference response rate with built-in 3- and 7-day reminders
  • AI sentiment scoring and red-flag detection on every response
  • Pay per check — no monthly subscription needed like Xref or Referoo
  • 3 free credits on sign-up, no credit card required
  • Sandbox keys (rc_test_) let you dry-run the full flow for free

Compare pricing and features on our alternatives page.

Setup checklist

Copy this sequence when scaffolding an integration or guiding a setup assistant:

  1. Create a sandbox API keySign up at verifyref.com, then open Dashboard → Developer settings and create an rc_test_ key (free, no emails sent).
  2. Validate the keyGET /api/v1/account with Authorization: Bearer rc_test_... to confirm the key works.
  3. Create a reference checkPOST /api/v1/checks with candidate details, references, questionnaireId, externalId + externalSource, and Idempotency-Key header.
  4. Register a webhookPOST /api/v1/webhooks subscribing to check.completed, or use the dashboard after signing in.
  5. Verify inbound signaturesValidate X-VerifyRef-Signature (HMAC-SHA256) on every inbound webhook POST.
  6. Write results to your ATSOn check.completed, use externalId to match the ATS record and store dashboardUrl and reportUrl.

What you can build

ATS automations

Fire a check from Bullhorn, Zoho, Greenhouse, or your homegrown ATS the moment a candidate hits the “Reference” stage.

Compliance workflows

Stream signed events into your audit pipeline. Each delivery is timestamped, signed, and replayable.

Branded portals

Pull completed checks (with AI sentiment + red-flag analysis) into your client or candidate portal via GET /checks/:id.

Quick start

  1. Grab a sandbox key. Sign up free, then open Dashboard → Developer settings (requires login) and create an rc_test_ key — free, no credits charged, no real emails sent.
  2. Create a check. Pass externalId + externalSource so we can correlate the result back to your ATS record. Set questionnaireId to a template ID from Templates in the dashboard.
  3. Listen for webhooks. Register a URL once; we POST signed events as the check progresses.

cURL — create a check (sandbox)

curl -X POST https://verifyref.com/api/v1/checks \
  -H "Authorization: Bearer rc_test_..." \
  -H "Idempotency-Key: ats-app-12345" \
  -H "Content-Type: application/json" \
  --data-raw '{
    "candidateName": "Jane Doe",
    "candidateEmail": "jane@example.com",
    "externalId": "12345",
    "externalSource": "bullhorn",
    "metadata": { "requisitionId": "REQ-99" },
    "questionnaireId": "YOUR_TEMPLATE_ID",
    "references": [
      { "name": "Ref Name", "email": "ref@example.com", "relationship": "Manager" }
    ]
  }'

Node — verify an inbound webhook

import crypto from "node:crypto";

export function verifyVerifyRef(rawBody: string, signature: string, secret: string) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Authentication

Every request uses a Bearer token in the Authorization header. Generate keys in Dashboard → Developer settings (requires login) — only the team owner can create or revoke them. You can also manage keys programmatically once you have a live key.

Authorization: Bearer rc_live_7d8f...

rc_live_…

Live keys. Each created check bills 1 credit and sends real emails to candidates and references.

rc_test_…

Sandbox keys. Free, no credits charged, no emails sent. Use these in development, CI, and integration tests.

Keep secrets server-side. Never embed an API key in a browser, mobile app, or public repo. Rotate immediately if a key is exposed.

Base URL & versioning

https://verifyref.com/api/v1

All examples on this page use VerifyRef's production API host (https://verifyref.com). API keys work against this URL whether you read these docs locally or on verifyref.com — examples never use a dev-only host.

Every response includes an X-VerifyRef-Version header so you can pin behavior. Breaking changes always ship under a new version date.

Idempotency

Network retries are inevitable. Send the same Idempotency-Key header on POST /checksand we'll return the original check instead of creating a duplicate.

  • Use a stable, unique value per logical request (e.g. your ATS application ID).
  • Replays return the same response shape with idempotentReplay: true.
  • Keys are scoped per team; rotate freely between live and sandbox.

Endpoints

GET/account

Returns your team name and live credit balance. Use it to validate an API key before kicking off a batch job.

{ "data": { "team": "Acme Corp", "credits": 150 } }
GET/checks

List your team's checks with pagination and filters. Combine externalId + externalSource to find the check matching a record in your ATS.

  • externalId, externalSource — ATS correlation filters
  • statusAWAITING_CONSENT, SENT, IN_PROGRESS, COMPLETED, EXPIRED
  • jobId, createdAfter — narrow by job or ISO timestamp
  • page (default 1), limit (default 20, max 100)
POST/checks

Create a reference check. On live keys this sends the candidate consent email and debits 1 credit. On sandbox keys nothing is emailed and no credit is charged.

Body

  • candidateName * — string
  • candidateEmail * — string
  • references * — array of { name, email, relationship } (skip if candidateProvidedReferences: true)
  • questionnaireId — ID from Templates in the dashboard, or pass questions inline
  • jobId / newJob — associate with a job (optional)
  • externalId + externalSource — recommended: pair your ATS record ID with one of bullhorn, zoho_recruit, sap_successfactors, workday, greenhouse, lever, other
  • metadata — free-form JSON echoed back on webhooks

Success (201)

{
  "success": true,
  "checkId": "clx...",
  "status": "AWAITING_CONSENT",
  "jobId": "job_...",
  "externalId": "12345",
  "externalSource": "bullhorn",
  "sandbox": false
}
GET/checks/:id

Full check detail, including each reference response, AI sentiment, red-flag scores, and signed dashboard / PDF report URLs.

{
  "data": {
    "id": "clx...",
    "status": "COMPLETED",
    "candidate": { "name": "John Doe", "email": "john@example.com" },
    "externalId": "12345",
    "externalSource": "bullhorn",
    "metadata": { "requisitionId": "REQ-99" },
    "dashboardUrl": "https://verifyref.com/check/clx...",
    "reportUrl": "https://verifyref.com/api/export/check/clx...",
    "references": [
      {
        "name": "Jane Smith",
        "relationship": "Manager",
        "status": "COMPLETED",
        "sentiment": { "score": 0.9, "label": "POSITIVE", "analysis": "..." },
        "redFlags": { "score": 0, "flags": [], "analysis": "No red flags." },
        "responses": [{ "question": "Would you hire them again?", "answer": "Yes." }]
      }
    ]
  }
}
PATCH/checks/:id

Update a check after creation. Supported fields:

  • metadata — merge / replace your ATS payload
  • status: "EXPIRED" — close out a check (fires check.status_changed)
  • emailRemindersEnabled — pause the 3-day / 7-day reminders

Webhooks

Register HTTPS endpoints in Dashboard → Developer settings (requires login) or via POST /webhooks. We POST a signed JSON payload for every subscribed event, retry on failure with exponential backoff, and surface delivery status in your dashboard.

Events

check.created

A check was created (API or dashboard).

check.consent_given

Candidate gave consent; reference emails are about to go out.

check.status_changed

Any status transition (consent → sent → completed → expired).

reference.responded

A reference submitted their questionnaire (fires per reference).

check.completed

Every reference has responded; AI analysis is final.

email.bounced

A candidate or reference email bounced — action may be required.

Payload

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "event": "check.completed",
  "timestamp": "2026-05-20T10:30:00Z",
  "data": {
    "checkId": "clx...",
    "candidateName": "Jane Doe",
    "candidateEmail": "jane@example.com",
    "status": "COMPLETED",
    "externalId": "12345",
    "externalSource": "bullhorn",
    "metadata": { "requisitionId": "REQ-99" },
    "dashboardUrl": "https://verifyref.com/check/clx...",
    "reportUrl": "https://verifyref.com/api/export/check/clx...",
    "completedAt": "2026-05-20T10:30:00Z"
  }
}

Headers: X-VerifyRef-Event, X-VerifyRef-ID, X-VerifyRef-Signature (HMAC-SHA256 of the raw body). Treat X-VerifyRef-ID as the dedup key.

Test before you ship

Point a webhook at https://verifyref.com/api/webhooks/echo and hit “Send test event” in the dashboard. The echo endpoint always returns HTTP 200 and confirms receipt via received: true, event, eventId, hasSignature, and bodyBytes — it does not echo the request body back (by design, for security).

Delivery contract: HTTPS endpoint, respond 2xx within 10 seconds, idempotent by X-VerifyRef-ID. We retry up to 3 times with exponential backoff and persist the last 25 attempts per endpoint.

Errors & rate limits

Errors always return JSON in the shape { "error": { "code", "message", "details?" } }. The v1 rate limit is 100 requests/minute per API key.

400Body failed schema validation. Inspect `details.fieldErrors`.
401Missing or unknown Bearer token.
402Team is out of credits — purchase a pack from billing.
403API key is valid but cannot access this resource.
404Resource does not exist or belongs to another team.
409A check with this externalId + externalSource already exists.
429Slow down; respect retry-after when present.
500Something went wrong on our side — safe to retry.

For AI assistants & agents

Building a setup assistant on top of VerifyRef? Anchor on these public, crawlable resources (no login required):

Dashboard URLs (/team/api, /team/integrations) require the user to sign in. For unattended setup, use the REST API with a key the user provides, or direct them to /sign-up first. Default to sandbox keys (rc_test_) when scaffolding — no credits charged, no emails sent.