Getting Started with Xident

Xident is a backend-first integration: your server creates a verification session, sends the user to the Xident widget, and reads the result back — all with your secret key. No frontend SDK required.

How it works

  1. Your backend calls POST /verify/v1/init and gets a one-time verify_url.
  2. You redirect the user to that verify_url (the Xident widget).
  3. The user verifies (liveness, age check, and/or document capture).
  4. Xident redirects back to your callback_url with a result token.
  5. Your backend calls GET /verify/v1/result/{token} to read the outcome.

Prerequisites

  • A Xident account (sign up here)
  • A project with a secret API key (sk_live_…)
  • A callback URL on your domain (HTTPS required in production; http://localhost allowed in development)

Step 1: Get your secret key

  1. Log in to dashboard.xident.io
  2. Click "Create Project" and enter your domain
  3. Copy your secret key (sk_live_…) and store it as a server-side environment variable — never expose it in client-side code

One key for the whole flow

The secret key (sk_live_) authenticates both POST /verify/v1/init and GET /verify/v1/result/{token} via the X-API-Key header. A publishable key (pk_live_) also exists for optional client-side widget embedding (see Core Concepts), but it is not needed for the standard backend integration.

Step 2: Create a verification session (backend)

When the user starts verification, your backend calls POST /verify/v1/init and redirects them to the returned verify_url:

Node.js

// Backend route: create a verification session with your SECRET key,
// then send the user to the returned verify_url.
app.get('/start-verification', async (req, res) => {
  const response = await fetch('https://api.xident.io/verify/v1/init', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.XIDENT_SECRET_KEY, // sk_live_...
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      callback_url: 'https://yoursite.com/verified',
      min_age: 18,
      user_id: req.user?.id, // optional — echoed back on the callback
    }),
  });

  const { data } = await response.json();
  // data.verify_url = https://verify.xident.io?t=xit_...
  res.redirect(data.verify_url);
});

Python

# Backend route: create a verification session with your SECRET key,
# then send the user to the returned verify_url.
@app.route('/start-verification')
def start_verification():
    response = requests.post(
        'https://api.xident.io/verify/v1/init',
        headers={'X-API-Key': os.environ['XIDENT_SECRET_KEY']},  # sk_live_...
        json={
            'callback_url': 'https://yoursite.com/verified',
            'min_age': 18,
            'user_id': current_user.id,  # optional — echoed back on the callback
        },
    )
    data = response.json()['data']
    # data['verify_url'] = https://verify.xident.io?t=xit_...
    return redirect(data['verify_url'])

curl

curl https://api.xident.io/verify/v1/init \
  -X POST \
  -H "X-API-Key: sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{"callback_url": "https://yoursite.com/verified", "min_age": 18}'

The response contains the one-time init token and the URL to send the user to:

{
  "success": true,
  "data": {
    "token": "xit_9f8e7d6c5b4a39281706f5e4d3c2b1a0",
    "verify_url": "https://verify.xident.io?t=xit_9f8e7d6c5b4a39281706f5e4d3c2b1a0"
  }
}

Step 3: The user verifies

After you redirect the user to verify_url, they complete verification on verify.xident.io. You don't build any UI — the widget handles liveness, age estimation, and document capture as required.

Step 4: Handle the callback

When verification finishes, Xident redirects the user back to your callback_url with query parameters:

https://yoursite.com/verified?token=xtk_abc123&status=success

The token here is the result token (xtk_…), which is different from the one-time init token (xit_…) carried in the verification URL as ?t=. Pass this xtk_ token to the result endpoint in Step 5.

Callback parameters

ParameterDescription
tokenResult token (xtk_…) — pass to GET /verify/v1/result/{token}
statussuccess, failed, or cancelled
user_idYour user_id if you provided one at init

Step 5: Fetch the result (backend)

Always read the result server-side with your secret key — never trust the callback status alone.

Node.js

app.get('/verified', async (req, res) => {
  // token is the RESULT token (xtk_...) returned on the callback.
  const { token, status } = req.query;

  if (status === 'cancelled') return res.redirect('/verification-cancelled');
  if (status !== 'success') return res.redirect('/verification-failed'); // status === 'failed'

  try {
    const response = await fetch(
      'https://api.xident.io/verify/v1/result/' + token,
      { headers: { 'X-API-Key': process.env.XIDENT_SECRET_KEY } } // sk_live_...
    );

    const { success, data } = await response.json();

    // data.status is the authoritative outcome: 'completed' (passed) | 'failed' | 'canceled'
    if (success && data.status === 'completed') {
      req.session.ageVerified = true;
      return res.redirect('/content');
    }
  } catch (error) {
    console.error('Verification error:', error);
  }

  return res.redirect('/verification-failed');
});

Python

@app.route('/verified')
def handle_verification():
    token = request.args.get('token')   # RESULT token (xtk_...) from the callback
    status = request.args.get('status')

    if status == 'cancelled':
        return redirect('/verification-cancelled')
    if status != 'success':  # status == 'failed'
        return redirect('/verification-failed')

    response = requests.get(
        f'https://api.xident.io/verify/v1/result/{token}',
        headers={'X-API-Key': os.environ['XIDENT_SECRET_KEY']},  # sk_live_...
    )

    body = response.json()

    # data['status'] is the authoritative outcome: 'completed' | 'failed' | 'canceled'
    if body.get('success') and body['data'].get('status') == 'completed':
        session['age_verified'] = True
        return redirect('/content')

    return redirect('/verification-failed')

Verification response

The result endpoint returns the Xident API envelope:

{
  "success": true,
  "data": {
    "token": "xtk_abc123",
    "status": "completed",
    "age_result": { "method": "age_estimation", "passed": true },
    "country_code": "US",
    "created_at": "2026-03-30T10:30:00Z",
    "expires_at": "2026-03-30T10:40:00Z"
  },
  "meta": {
    "request_id": "req_xyz789",
    "timestamp": "2026-03-30T10:30:05Z"
  }
}

data.status is the authoritative outcome (completed = passed, failed, canceled). Sub-objects such as age_result, liveness_result, and ocr_result carry method-level detail — see the API Reference for the full schema.

Testing

For development, use your test key and a localhost callback:

  • sk_test_… secret key (sandbox mode)
  • http://localhost:* callback URLs (no HTTPS required)

Next Steps