Skip to main content
A webhook subscription sends events to your HTTPS endpoint without a URL on every call. You register an endpoint once, then pick the events it should receive:
  • every call of one agent, or of the whole workspace, including inbound calls to your numbers and WhatsApp calls
  • campaign lifecycle: started, paused, resumed, finished, stopped
  • wallet alerts: balance low, calls refused for balance, balance back up
  • payments: payment received, payment failed
The per-call webhook_url, the campaign webhook_url and a phone number’s webhook_url keep working as described in Webhooks. If you use both for the same call or campaign, both receive it.
In the console, open Webhooks to add an endpoint and tick events from a checklist. Everything on this page is the same feature through the API.

Set it up

All routes use your API key and act on the key’s workspace.
1

Create an endpoint

Response (201)
signing_secret is shown only in this response. Store it now. Reads never return it again.
The URL must be HTTPS on port 443. Optional headers (up to 16) are stored encrypted, and reads show only their names.
2

Subscribe it to events

For one agent only, use "scope": {"type": "agent", "agent_id": "agt_…"}. Wallet and payment events belong to the whole workspace, so an agent subscription cannot list them (the API answers 400).
3

Send a test

This sends a real, signed request to your endpoint with made-up data and "test": true. The 202 response is the queued delivery. Look it up under deliveries.
GET /v2/webhooks/event-types lists every event with its label, group, one-line description, scopes, JSON schema and an example payload.

Event types

Calls

Scope: one agent or the whole workspace. data.call is the call object.

Campaigns

Scope: one agent (the campaigns that agent runs) or the whole workspace. data.campaign is the same object, with the same event id, that the campaign’s own webhook_url receives.

Wallet and payments

Scope: the whole workspace only. The balance in these events is the one GET /v2/wallet shows: what you can spend, after calls in progress. We check it about once a minute, so wallet.balance_low reaches you within a minute of the crossing. A top-up, a call or an API charge can each cause one. If several workspaces share your company’s wallet, each workspace with a subscription receives the payment events.

Low balance alert level

The alert level is ₹500 until you change it.
Response
GET /v2/webhooks/settings reads it. Set it to 0 to turn wallet.balance_low off; wallet.depleted still fires. Pass if_revision if you want a stale write refused.

Payloads

Every event has the same envelope.
required_inr is what the refused call needed to start. data.call is absent when a campaign paused before placing a call.
kind is top_up, monthly_payment, plan_upgrade or subscription. amount_inr is the amount credited, before GST. payment.failed carries the same payment object with a reason in the bank’s words.
Each event type’s full JSON schema is in GET /v2/webhooks/event-types.

Verify the signature

Every delivery is signed with the endpoint’s signing_secret, using the same scheme as call webhooks:
v1 is the lowercase hex HMAC-SHA256(signing_secret, "<t>.<raw_body>"). Reject a timestamp more than 300 seconds from now, and compare in constant time.
Verify the raw bytes you received, before parsing the JSON. Rotating the secret. POST /v2/webhooks/endpoints/{id}/rotate-secret with {"if_revision": N} returns a new secret that starts signing five minutes later. Install it alongside the old one before then, and keep the old one for an hour. X-Mirai-Key-Version tells you which secret signed a delivery.

Deliveries and retries

Delivery is at least once. Return any 2xx after you have stored the event; store id with a unique constraint so a repeat does nothing. Events can arrive out of order, so act on created_at and the object’s state, not arrival order. A failed delivery is retried after 1 second, 7 seconds, 49 seconds, about 6 minutes, then every 30 minutes, for up to 24 hours. A Retry-After header from you is respected.

Manage endpoints and subscriptions

Creating an endpoint, rotating, testing and retrying accept an Idempotency-Key header, so a retried request never creates a second endpoint or secret. Two subscriptions that match the same event for the same endpoint produce one delivery.

Checklist

  • Endpoint is public HTTPS on port 443 and answers 2xx within a few seconds.
  • signing_secret stored; signature checked on the raw body; old timestamps rejected.
  • Events stored by id with a unique constraint.
  • Alert level set to the balance at which you want to top up.
  • A test event sent and seen in your logs.