# Send a verification code

```http
POST https://smsprovider-web.vercel.app/api/v1/otp/send
```

Sends a one-time code (4–8 digits, default 6) as a regular SMS from the sender name OTP to an Israeli mobile. The code is generated and checked by us, never stored (only a keyed hash) and never returned to you. Limit: 3 codes per phone per 10 minutes, 10 per hour.

**Authentication:** `Authorization: Bearer bm_live_…` · **Required scope:** `otp`

> Send an `Idempotency-Key` header (a unique string, e.g. a UUID). Repeating the same key within 24 hours returns the same response without charging again.

## Request body

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `to` | string | yes | len 5–20 |
| `app_id` | string | no | pattern `^[A-Za-z0-9_-]{1,32}$` |
| `max_tries` | integer | no | 3–5 |
| `valid_minutes` | integer | no | 1–15 |
| `code_length` | integer | no | 4–8 |
| `text` | string | no | len 6–300 |

## Response

`200` — `OtpSendResult`

```json
{
  "session_id": "c3a1b2d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "expires_at": "2026-11-02T18:05:00Z"
}
```

## Errors

| Status | Code |
| --- | --- |
| 400 | `validation_error` |
| 429 | `otp_rate_limited` |
| 402 | `insufficient_credits` |
| 422 | `invalid_destination` |
| 401 | `unauthorized` |
| 403 | `insufficient_scope` |
| 429 | `rate_limited` |
| 500 | `internal_error` |

## Examples

### curl
```bash
curl -X POST "https://smsprovider-web.vercel.app/api/v1/otp/send" \
  -H "Authorization: Bearer $BATLER_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"to":"0501234567","app_id":"login","valid_minutes":5,"text":"קוד הכניסה שלך ל-MyBrand: [code]"}'
```
### Node.js
```ts
import { BatlerSMS } from "@batler/sms";

const sms = new BatlerSMS({ apiKey: process.env.BATLER_API_KEY! });
const body = {
  "to": "0501234567",
  "app_id": "login",
  "valid_minutes": 5,
  "text": "קוד הכניסה שלך ל-MyBrand: [code]"
};
const result = await sms.otp.send(body);
```
### PHP
```php
<?php
$ch = curl_init("https://smsprovider-web.vercel.app/api/v1/otp/send");
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer " . getenv("BATLER_API_KEY"),
    "Content-Type: application/json",
    "Idempotency-Key: " . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => json_encode(["to" => "0501234567", "app_id" => "login", "valid_minutes" => 5, "text" => "קוד הכניסה שלך ל-MyBrand: [code]"], JSON_UNESCAPED_UNICODE),
]);
$result = json_decode(curl_exec($ch), true);
```
### Python
```python
import os, uuid, requests

resp = requests.request(
    "POST", "https://smsprovider-web.vercel.app/api/v1/otp/send",
    headers={"Authorization": f"Bearer {os.environ['BATLER_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
    json={"to": "0501234567", "app_id": "login", "valid_minutes": 5, "text": "קוד הכניסה שלך ל-MyBrand: [code]"},
    timeout=30,
)
resp.raise_for_status()
result = resp.json()
```
### C#
```csharp
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new("Bearer", Environment.GetEnvironmentVariable("BATLER_API_KEY"));
var req = new HttpRequestMessage(HttpMethod.Post, "https://smsprovider-web.vercel.app/api/v1/otp/send");
req.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
req.Content = new StringContent("{\"to\":\"0501234567\",\"app_id\":\"login\",\"valid_minutes\":5,\"text\":\"קוד הכניסה שלך ל-MyBrand: [code]\"}", System.Text.Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);
var result = await res.Content.ReadAsStringAsync();
```
