# Send a Voice OTP

> POST /v1/voice-otp/send - call an Indian mobile number and read a one-time code aloud.

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

`POST https://voice-api.edesy.in/v1/voice-otp/send`

## Request body

| Field | Type | Required | Description |
|---|---|---|---|
| `phone_number` | string | yes | Indian mobile number, 10 digits (`+91`/`91`/`0` prefix is removed) |
| `otp_code` | string | no | 4-10 characters. Omit to get a generated 6-digit code |
| `message_template` | string | no | Spoken text. `{{otp}}` is replaced by the code, e.g. `"Your Acme code is {{otp}}. I repeat, {{otp}}."` |
| `gather_enabled` | boolean | no | Ask the user to press a key to confirm; the key is returned as `dtmf_response` |
| `callback_url` | string (URL) | no | Where we POST the result. Overrides the default in settings |
| `external_id` | string | no | Your reference (max 255), returned in the webhook and filterable in logs |
| `metadata` | object | no | Any JSON, returned in the webhook |

Defaults for the template, press-1 confirmation and callback URL can be set once in the dashboard settings.

## Response `201`

```json
{
  "data": {
    "id": "5b1c2d3e-0000-4000-8000-000000000000",
    "call_sid": "a1b2c3",
    "phone_number": "9876543210",
    "otp_code": "482913",
    "status": "initiated",
    "created_at": "2026-09-26T10:15:12Z"
  },
  "meta": { "timestamp": "2026-09-26T10:15:12Z" }
}
```

## Errors

`400 invalid_request`, `400 validation_error`, `400 invalid_phone`, `402 insufficient_balance`, `429 rate_limit_exceeded`. See [Error Codes](https://edesy.in/docs/voice-otp/api-reference/errors).
