API Reference

Webhooks

Webhooks let you receive real-time HTTP notifications when events happen in your organization: a face is enrolled, an identification succeeds, or a liveness check fails. LiveXFace sends a POST request to your endpoint with a JSON payload describing the event.

Registering a webhook endpoint

Webhooks are registered from the dashboard under Webhooks → Create Webhook. Webhook management endpoints are CORS-restricted to the dashboard and cannot be called from external applications.

When registering, provide:

  • URL: The HTTPS endpoint on your server that will receive events.
  • Events: Select which event types to subscribe to (see the table below).
  • Secret: Generated for you when the webhook is created and shown once, on that screen. Copy it then — it is what you check the signature against, and it is not displayed again. If it is lost or may have leaked, rotate it (see below).
The Webhooks page in the LiveXFace console. A table lists two endpoints by URL, the events each is subscribed to shown as tags, an active toggle, and actions to view deliveries, edit or delete.
One row per endpoint. The list icon under Actions opens that endpoint's delivery history.

Event types

EventTrigger
face.registeredA face was enrolled into a collection.
face.identifiedA 1:N search found at least one match above the threshold.
face.verifiedA 1:1 check ran. Read data.match for the outcome — a non-match fires this event too.
face.deletedA face was removed from a collection.
collection.createdA collection was created.
collection.deletedA collection was deleted.
member.invitedSomeone was invited to the organization.
member.removedSomeone was removed from the organization.
api_key.createdAn API key was issued.
api_key.revokedAn API key was revoked.

Webhook payload structure

JSON
{
  "id": "0c772a2c-af02-413e-9ef0-c7da186d724d",
  "event": "face.identified",
  "organizationId": "8b1f4d2a-51c7-4f9e-9a3b-6d0e5c4a7b21",
  "timestamp": "2026-09-20T11:22:33Z",
  "data": {
    "faceId": "dc3e7a57-22d5-4271-b707-213e49c8fe54",
    "externalId": "user_alice_001",
    "collectionId": "9f1c2b7e-3d84-4a16-8c55-0b7e2a1d6f30",
    "confidence": 0.97,
    "totalMatches": 1,
    "queryTimeMs": 42
  }
}

Signature verification

Every webhook request includes a signature header so you can verify it came from LiveXFace and not a third party. The signature is a HMAC-SHA256 of the raw request body using your webhook secret.

Shell
X-Webhook-Event: face.identified
X-Webhook-Signature: sha256=a1b2c3d4e5f6...
Content-Type: application/json
HeaderDescription
X-Webhook-EventThe event name, so you can route without parsing the body first.
X-Webhook-SignatureHMAC-SHA256 of the raw request body, prefixed with sha256=. Sent only when the webhook has a secret.

Verify the signature in your webhook handler:

import crypto from 'crypto'

function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(signature.replace('sha256=', ''), 'hex'),
    Buffer.from(expected, 'hex')
  )
}

// Express handler
app.post('/webhooks/livexface', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-webhook-signature']
  if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature')
  }
  const event = JSON.parse(req.body)
  console.log('Event:', event.event, event.data)
  res.sendStatus(200)
})

Rotating the secret

Use Rotate secret on the webhook in the console when the secret is lost or may have leaked. You get a new one, shown once. The old secret stops working at that moment: every delivery after it is signed with the new one, so put the new secret on your receiving server straight away.

Retries and delivery

A delivery counts as successful when your endpoint answers with a 2xx inside 10 seconds. Anything else — a non-2xx status, a timeout, a DNS or TLS failure, a refused connection — is a failure and is retried.

There are up to four attempts in total, spaced one second, two seconds and four seconds apart. The whole sequence is over in about seven seconds, so retries cover a brief blip, not an outage. After the fourth attempt the delivery stops and is recorded with its last status code and response body, which you can read under Webhooks → Deliveries in the console.

Because retries are fast and few, treat your handler as the durable part: acknowledge with a 2xx as soon as you have the payload, and do the slow work afterwards. Events carry an id, so store it and ignore a repeat.

Manage webhooks

MethodPathDescription
GET/api/v1/organizations/{org_id}/webhooksList webhooks
POST/api/v1/organizations/{org_id}/webhooksCreate a webhook. The secret is returned once, here only.
PATCH/api/v1/organizations/{org_id}/webhooks/{webhook_id}Update the URL, events or active flag
POST/api/v1/organizations/{org_id}/webhooks/{webhook_id}/rotate-secretReplace the signing secret. The new one is returned once; the old one stops working immediately.
DELETE/api/v1/organizations/{org_id}/webhooks/{webhook_id}Delete a webhook
GET/api/v1/organizations/{org_id}/webhooks/{webhook_id}/deliveriesDelivery history for one webhook