Webhooks
VERYO tells your server when a code is delivered and verified, so you do not need to poll the API. The endpoint, events and secret are set in the dashboard, in the Webhooks section. There you can also send a webhook.test test event and view the delivery log.
The endpoint must start with https:// and must not point to an internal network.
Events
| Event | When | data fields |
|---|---|---|
verification.delivered |
A channel delivered the code | verification_id, phone, channel, cost_tiyn |
verification.verified |
The user entered the correct code | verification_id, phone, status |
verification.failed |
Entry attempts or channels ran out | verification_id, phone, status; reason, if delivery failed |
correlation_id is added to data if it was passed in the request. No event is sent when a code expires.
{
"id": "evt_1a2b3c4d5e6f70819a2b",
"type": "verification.delivered",
"created_at": "2026-11-08T10:00:03Z",
"data": {
"verification_id": "vrf_8c1f04a2b7d93e6f5a10",
"phone": "+77011234567",
"channel": "telegram",
"cost_tiyn": 900,
"correlation_id": "order-42"
}
}
Signature verification
| Header | Value |
|---|---|
X-Veryo-Event-Id |
Event identifier |
X-Veryo-Timestamp |
Send time, Unix seconds |
X-Veryo-Signature |
sha256= and the hex of HMAC-SHA256(secret, "<timestamp>.<raw body>") |
The signature is computed over the raw request body, before JSON parsing:
import { createHmac, timingSafeEqual } from 'node:crypto'
function verify(rawBody, timestamp, signature, secret) {
const hash = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')
const expected = Buffer.from(`sha256=${hash}`)
const got = Buffer.from(signature)
return got.length === expected.length && timingSafeEqual(got, expected)
}
The secret is issued the first time you save the settings. When you rotate it in the dashboard, the old secret stops working immediately.
Response and retries
Respond with a 2xx code within 10 seconds. Redirects are not followed. After a failure, VERYO retries after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 15 hours, for 7 attempts in total.
Delivery is at-least-once: the same event may arrive twice. Discard duplicates by the event
id.