# SafeCode Messaging & Bulk SMS API > Send SMS, or provision WhatsApp verification numbers, to mobile numbers from your own backend. Single sends, batches of up to 100, and background broadcasts of up to 500. One API key, a prepaid client wallet, and a refund whenever the provider fails. Base URL: https://api.safecode.vip/v1 Auth: `Authorization: Bearer sfcd_live_…` (sandbox keys are `sfcd_test_…`) Errors: `{ "error": "", "message": "…", "request_id": "…" }` with a matching HTTP status Rate limits: `X-RateLimit-Limit`, `-Remaining`, `-Reset`, `-Policy` on every response; `Retry-After` on 429 Countries: Ghana (`GH`, `+233…`) today. You compose the message body; for OTPs you generate and verify the code on your side. ## Reference - [Full API reference (Markdown)](https://safecode.vip/developer-apis/messaging.md): Every endpoint, field, response, webhook event and error code. Read this first. - [Human docs page](https://safecode.vip/developer-apis/messaging): The same content rendered for people. - [Dashboard](https://safecode.vip/otp-delivery-api): Create keys, fund the client wallet, register webhooks, accept bulk-messaging terms. ## Endpoints - POST /messages/send: one message to one number; `channel` is `sms` (default) or `whatsapp`; supports `Idempotency-Key` - POST /messages/send-batch: up to 100 independent messages in one call; per-item `channel`; 200 all sent, 207 partial, 402 none - POST /messages/bulk: one message to up to 500 recipients, run in the background; `action` is `estimate`, `send` (202 + `job_id`) or `status` - GET /messages/status?id=: delivery state of a message - GET /balance: client wallet balance and allowed countries ## Scopes (dashboard keys carry all of these) - `otp:send` → /messages/send - `messages:send` (or `sms:send`, `otp:send`) → /messages/send-batch - `sms:send` (or `otp:send`) → /messages/bulk - `otp:read` → /messages/status - `balance:read` → /balance ## Notes for integrators - WhatsApp: pass `"channel": "whatsapp"`; the response adds `whatsapp_phone`, the number allocated for the recipient's verification. - Every send debits the wallet at dispatch and refunds automatically if the provider rejects it. `insufficient_balance` is HTTP 402. - Bulk sends reserve the full estimated cost up front and refund the unused part when the job completes; use `action: "estimate"` to see the cost (and SMS part count) before committing. - Messages over one SMS part are billed per part: 160 chars/part for `gsm7`, 70 for `ucs2` (emoji or non-GSM characters). - Webhooks are signed: `X-SafeCode-Signature: t=,v1=` over `"."` with HMAC-SHA256. Retries: 6 attempts, 1m → 5m → 30m → 2h → 12h → 24h. - `message.*` webhook events alias the legacy `otp.*` names; subscribe to either. ## Related - [Numbers API](https://safecode.vip/developer-apis/numbers/llms.txt): The other direction: rent a number and receive codes. - [Site index](https://safecode.vip/llms.txt)