Skip to main content
Webhooks are self-serve. Create, edit and delete them yourself with your API key — there is nothing to request and nobody to email. A webhook is an HTTPS URL we POST a signed JSON envelope to when something happens on your account. Use them instead of polling GET /api/v1/orders/{id} in a loop.
Base path: https://virtualsms.io/api/v1/customer/webhooks. Authenticate with the same x-api-key header as every other endpoint — including a key minted through the x402 top-up flow.

Event types

Exactly five event types exist. Subscribing to anything else is rejected with 400. balance.low requires a threshold; the other four do not.

Create a webhook

secret is returned exactly once, in this create response. Store it now — no other endpoint will ever return it, and there is no “show secret” call.

URL rules

The URL is validated on create and on update. It must:
  • use https:// — http:// and every other scheme are rejected
  • resolve to a public host — loopback, private and link-local hosts are rejected
  • be at most 2048 characters

Manage webhooks

GET list returns { "success": true, "webhooks": [...], "count": N }. DELETE returns { "success": true, "id": "3f2a91c4-8e5b-4d17-9a02-c1b6e7f45d80" }. PATCH accepts any subset of the updatable fields; sending none returns 400. Manually setting paused: false also resets the consecutive-failure counter to zero.

Test-fire

The test event uses the first event type the endpoint is subscribed to. The endpoint must be active and not paused, or the call returns 400.

Delivery history

Returns { "success": true, "deliveries": [...], "count": N, "limit": 50, "offset": 0 }. Each delivery carries id, event_id, event_type, attempt, status, response_status, response_body, scheduled_for, delivered_at, error_message, created_at and the full payload that was sent. limit defaults to 100 and is capped at 500.

The envelope we POST

Every event — including the test event — has the same envelope shape:
id is a ULID-suffixed event id, unique per event and stable across retries — use it to deduplicate. The contents of data vary by event type.

Headers

Verifying the signature

Compute the HMAC over the raw request body bytes, before any JSON parsing, and compare in constant time.

Retries and auto-pause

  • Return any 2xx status to acknowledge. Anything else — including a timeout — is a failure.
  • Each request times out after 5 seconds.
  • Up to 5 attempts per event. Attempt 1 fires immediately; the gaps after a failed attempt are 1 minute, 5 minutes, 30 minutes, 2 hours. After the fifth failure the delivery is marked a permanent failure and is not retried.
  • A successful delivery resets your endpoint’s consecutive-failure counter to zero.
  • After 20 consecutive failures the endpoint is auto-paused and stops receiving events. Un-pause it with PATCH {"paused": false}, which also clears the counter.
Deliveries queued while an endpoint is inactive or paused are skipped rather than held.

Dashboard

Everything on this page is also available in the dashboard under Settings → Webhooks.