Skip to main content

Background Check API Quickstart (Vanilla JavaScript)

This guide shows how to get a JWT and make your first calls to the Verification API using a single, dependency‑free Node.js script written in plain JavaScript. The script was derived from the internal workflow test harness (workflow-test.ts) and simplified for client use: it acquires a token, checks API health, creates a verification, and (optionally) fetches its workflow status.

Prerequisites

  • Node.js 18+ (built‑in fetch is required)
  • API base URL for the target environment
  • Either a ready‑to‑use JWT or Auth0 Client Credentials to obtain one

Choose your environment

Set API_BASE_URL to point at your target environment:
export API_BASE_URL="https://sandbox.theary.ai"

Get a token

You can provide a token directly, or have the script fetch one via Auth0 Client Credentials.
  • Option A — Fetch a token via Auth0 Client Credentials:
export AUTH_DOMAIN="https://<your-auth-domain>"        # e.g., https://auth-dev.theary.ai
export AUTH_CLIENT_ID="<your-client-id>"
export AUTH_CLIENT_SECRET="<your-client-secret>"
export AUTH_AUDIENCE="https://<your-api-audience>"     # e.g., https://empv-auth-dev.theary.ai
  • Option B — Use an existing token:
export AUTH_TOKEN="<paste-your-jwt-here>"

Notes:

Your token should include the tenant claim expected by the API. If your machine‑to‑machine token doesn’t include it, ask your Theary contact to enable an Auth0 Action that injects the tenant claim, or use a token that already contains it. If both AUTH_TOKEN and Auth0 credentials are set, AUTH_TOKEN is used.

Run the quickstart

Save the full script below as verify-quickstart.js. Set environment variables (see above), then run:
node verify-quickstart.js
If successful, you’ll see health info, a created order with its verificationOrderId and searchIds, the order details, and the workflow status.

Full script (copy/paste as verify-quickstart.js)

#!/usr/bin/env node

/*
  Verification API Quickstart (Vanilla JS)
  - No external dependencies (uses Node 18+ built-in fetch)
  - Acquires a JWT (env var or Auth0 client credentials)
  - Calls /health, POST /background-check/v1/orders, and GET /background-check/v1/orders/{id}
*/

const DEFAULT_API_BASE_URL = process.env.API_BASE_URL || 'https://sandbox.theary.ai' // STAGING default

async function getAuthToken() {
  if (process.env.AUTH_TOKEN) {
    return process.env.AUTH_TOKEN
  }

  const { AUTH_DOMAIN, AUTH_CLIENT_ID, AUTH_CLIENT_SECRET, AUTH_AUDIENCE } = process.env

  if (!AUTH_DOMAIN || !AUTH_CLIENT_ID || !AUTH_CLIENT_SECRET || !AUTH_AUDIENCE) {
    throw new Error('Missing auth. Provide AUTH_TOKEN or set AUTH_DOMAIN, AUTH_CLIENT_ID, AUTH_CLIENT_SECRET, AUTH_AUDIENCE.')
  }

  const res = await fetch(`${AUTH_DOMAIN}/oauth/token`, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({
      client_id: AUTH_CLIENT_ID,
      client_secret: AUTH_CLIENT_SECRET,
      audience: AUTH_AUDIENCE,
      grant_type: 'client_credentials',
    }),
  })

  if (!res.ok) {
    const text = await res.text().catch(() => '')
    throw new Error(`Failed to fetch token: ${res.status} ${res.statusText} ${text}`)
  }

  const data = await res.json()
  if (!data.access_token) {
    throw new Error('No access_token returned by Auth0')
  }
  return data.access_token
}

function decodeJwtPayload(jwt) {
  try {
    const payloadPart = jwt.split('.')[1]
    return JSON.parse(Buffer.from(payloadPart, 'base64').toString('utf8'))
  } catch {
    return null
  }
}

async function getJson(url, headers) {
  const res = await fetch(url, { headers })
  if (!res.ok) {
    const text = await res.text().catch(() => '')
    throw new Error(`GET ${url} failed: ${res.status} ${res.statusText} ${text}`)
  }
  return res.json()
}

async function postJson(url, body, headers) {
  const res = await fetch(url, {
    method: 'POST',
    headers: { ...headers, 'content-type': 'application/json' },
    body: JSON.stringify(body),
  })
  if (!res.ok) {
    const text = await res.text().catch(() => '')
    throw new Error(`POST ${url} failed: ${res.status} ${res.statusText} ${text}`)
  }
  return res.json()
}

function buildSampleVerification(index = 1) {
  return {
    applicant: {
      firstName: 'John',
      lastName: `Smith-${index}`,
      ssn: `123-45-${String(6788 + index).padStart(4, '0')}`,
      birthday: '1990-05-15',
      phone: `+1-555-123-${String(4566 + index).padStart(4, '0')}`,
      email: `john.smith${index}@example.com`,
      signedReleaseFileUrl: 'https://example.com/signed-release.pdf',
      addresses: [
        {
          addressType: 'home',
          addressLine1: `${123 + index} Main Street`,
          addressLine2: 'Apt 4B',
          addressCity: 'New York',
          addressState: 'NY',
          addressZipCode: '10001',
          addressCountry: 'US',
          startDate: '2021-01-01',
        },
      ],
    },
    businessContext: {
      entityName: 'Microsoft Corporation',
      appliedJobTitle: 'Senior Software Developer',
      worksiteCity: 'New York',
      worksiteState: 'NY',
      proposedSalary: 100000,
    },
    searchTypes: [{ searchType: 'EMPLOYMENT' }],
  }
}

async function main() {
  const apiBaseUrl = DEFAULT_API_BASE_URL
  console.log(`API_BASE_URL: ${apiBaseUrl}`)

  const token = await getAuthToken()
  const tokenPreview = `${token.substring(0, 12)}...${token.substring(token.length - 12)}`
  console.log(`Token acquired: ${tokenPreview}`)

  const payload = decodeJwtPayload(token)
  if (payload && !payload.tenant) {
    console.warn("Warning: Token does not include 'tenant' claim; API may reject requests.")
  }

  const authHeaders = { Authorization: `Bearer ${token}` }

  // 1) Health check
  const health = await getJson(`${apiBaseUrl}/health`, authHeaders).catch(e => {
    throw new Error(`Health check failed: ${e.message}`)
  })
  console.log('Health:', JSON.stringify(health))

  // 2) Create a verification order
  const verificationRequest = buildSampleVerification(1)
  const created = await postJson(`${apiBaseUrl}/background-check/v1/orders`, verificationRequest, authHeaders)
  console.log('Created order:', JSON.stringify(created))

  const orderId = created?.verificationOrderId
  const firstSearchId = Array.isArray(created?.searchIds) && created.searchIds.length > 0 ? created.searchIds[0] : null

  // 3) Fetch order details (optional)
  if (orderId) {
    const order = await getJson(`${apiBaseUrl}/background-check/v1/orders/${orderId}`, authHeaders)
    console.log('Order details:', JSON.stringify(order))
  }

  // 4) Fetch workflow status (optional, legacy endpoint)
  if (firstSearchId) {
    const status = await getJson(`${apiBaseUrl}/verification/${firstSearchId}/workflow-status`, authHeaders)
    console.log('Workflow status:', JSON.stringify(status))
  } else {
    console.log('No searchIds returned; skipping status check.')
  }
}

main().catch(err => {
  console.error('Quickstart failed:', err.message)
  process.exitCode = 1
})