Skip to main content
Instead of polling the OTP.ID API to find out when a user has been verified, you can configure a webhook endpoint and receive a real-time push notification the moment verification succeeds. OTP.ID sends an HTTP POST to your URL immediately after a successful POST /v3/verify call or an automatic WhatsApp Inbound match. This makes webhooks especially important for WhatsApp Inbound flows, where your server is never part of the verification exchange.

Setup

Log in to the OTP.ID dashboard, navigate to Settings → Webhooks, and enter your endpoint URL. OTP.ID will begin delivering otp.verified events to that URL for all verified transactions on your account.

When the webhook fires

The otp.verified event is triggered in two situations:
  • A user submits the correct code to POST /v3/verify and the API returns "verified": true.
  • A user sends the correct WhatsApp Inbound message and OTP.ID matches the token automatically.

Delivery behaviour

OTP.ID delivers webhooks asynchronously — the HTTP POST to your endpoint happens in the background and does not block the API response your server receives. If delivery fails, OTP.ID retries according to the following policy: Each attempt has a 10-second timeout. Any non-2xx HTTP response or network-level failure (connection refused, DNS error, timeout) counts as a failure and triggers the next retry. After 3 retries without success, the event is abandoned.

Webhook payload

OTP.ID sends a JSON body with the following structure. The payload intentionally excludes the OTP code, any hash of it, or the raw verification token — only the metadata needed to identify and act on the event is included.
The webhook payload never contains the OTP code itself, any hash of it, or the WhatsApp Inbound token. Store only what you need from the payload; do not log the full request body if your logs are broadly accessible.

Request headers

Every webhook request includes two security headers you must validate:

Signature verification

Always verify the signature before processing a webhook event. Without this check, any party that discovers your webhook URL can send forged events and trigger actions in your system — for example, granting access to a user who never actually verified their number.
OTP.ID signs each request so you can confirm it originated from OTP.ID and has not been tampered with. The signed message is constructed by concatenating the timestamp, a period, and the raw JSON body:
Compute the expected HMAC-SHA256 using your webhook_secret (found in the OTP.ID dashboard under Settings → Webhooks) and compare it to X-OTPID-Signature using a constant-time comparison to prevent timing attacks.
Make sure you compute the HMAC over the raw request body string, not a re-serialised version of the parsed JSON. JSON serialisers may reorder keys or change whitespace, which would produce a different digest and cause every signature check to fail.

Complete webhook handler example

The following examples show a minimal but secure webhook handler that verifies the signature before doing anything else.

Best practices

Acknowledge quickly, process asynchronously. Your endpoint has 10 seconds to respond before OTP.ID considers the attempt failed and schedules a retry. Return 200 OK as soon as the signature is validated, then process the event in the background. This keeps your handler fast and prevents spurious retries caused by slow database writes or downstream API calls. Make your handler idempotent. OTP.ID may deliver the same event more than once if a retry fires after your first 200 was sent but not received. Use otp_id as a deduplication key — check whether you’ve already processed that transaction before taking action. Reject invalid signatures with HTTP 401. Do not return 200 for requests that fail signature validation. A 200 response tells OTP.ID the event was received successfully and no retry is needed, which would suppress the legitimate delivery. Keep your webhook_secret out of source code. Load it from an environment variable or a secrets manager. Rotate it in the OTP.ID dashboard if you suspect it has been compromised.