# Webhooks

> The voice-otp.completed webhook - payload, statuses and retries.

Source: https://edesy.in/docs/voice-otp/api-reference/webhooks

When a call ends we POST the result to the `callback_url` from the request (or the default in settings).

```
POST https://your-app.com/webhooks/voice-otp
Content-Type: application/json
X-Edesy-Event: voice-otp.completed
```

```json
{
  "id": "5b1c2d3e-0000-4000-8000-000000000000",
  "external_id": "signup-123",
  "phone_number": "9876543210",
  "status": "delivered",
  "dtmf_response": "1",
  "duration_sec": 18,
  "price": "1.5000",
  "metadata": { "user_id": 42 },
  "completed_at": "2026-09-26T10:15:30Z"
}
```

- `status`: `delivered`, `no-answer`, `busy` or `failed`.
- `dtmf_response`: the key the user pressed, when `gather_enabled` is on.
- `price`: amount charged in rupees.

Respond with any `2xx` status. If your endpoint fails, we retry up to 3 times.

**Tip:** on `no-answer` or `busy`, offer the user a "Call me again" button, or fall back to your SMS OTP.
