# Cast SMS API — Developer Documentation **Base URL:** `https://api.cast.ph` **API Version:** v1 --- ## Overview The Cast API allows you to send SMS, OTP, and SIM messages programmatically. All API requests must be authenticated using an API key provided by Cast. --- ## Authentication All requests to the SMS and OTP endpoints require an API key passed in the request header. **Header:** ``` X-API-Key: cast_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` API keys have the format `cast_` followed by 64 hexadecimal characters. Keep your API key secret — do not expose it in client-side code or public repositories. --- ## Endpoints ### 1. Send SMS **`POST /api/sms/send`** Sends an SMS message to the specified destination number. #### Request Headers | Header | Required | Value | |--------|----------|-------| | `X-API-Key` | Yes | Your API key | | `Content-Type` | Yes | `application/json` | #### Request Body ```json { "to": "09171234567", "message": "Hello, this is a test message.", "sender_id": "CAST" } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `to` | string | Yes | Recipient phone number. Must be an 11-digit Philippine mobile number (e.g. `09171234567`). | | `message` | string | Yes | Message content. Max 300 characters (2 SMS parts). Absolute limit is 450 characters (3 SMS parts). | | `sender_id` | string | No | Sender ID to use. Max 11 characters. Must be pre-approved. Defaults to your assigned sender ID if only one is configured. | #### Success Response — `200 OK` ```json { "success": true, "message_id": "abc123def456", "parts": 1 } ``` | Field | Type | Description | |-------|------|-------------| | `success` | bool | `true` if the message was sent. | | `message_id` | string | Gateway-assigned message identifier. | | `parts` | int | Number of SMS parts (standard SMS = 1 part per 160 characters). | --- ### 2. Send Bulk SMS **`POST /api/sms/bulk`** Sends the same SMS message to multiple recipients in a single API call. Up to **1,000 destinations** per request. Credits are checked upfront for the full batch before any messages are sent. Each destination is sent individually and logged separately, so partial success is possible if a send fails mid-batch. #### Request Headers | Header | Required | Value | |--------|----------|-------| | `X-API-Key` | Yes | Your API key | | `Content-Type` | Yes | `application/json` | #### Request Body ```json { "to": ["09171234567", "09181234567", "09191234567"], "message": "Hello, this is a broadcast message.", "sender_id": "CAST" } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `to` | array of strings | Yes | List of recipient phone numbers. Min 1, max 1,000. Each must be a valid phone number. | | `message` | string | Yes | Message content to send to all recipients. | | `sender_id` | string | No | Sender ID to use. Must be pre-approved. Defaults to your assigned sender ID if only one is configured. | #### Success Response — `200 OK` ```json { "success": true, "total": 3, "sent": 3, "failed": 0, "results": [ { "to": "09171234567", "success": true, "message_id": "abc123", "parts": 1 }, { "to": "09181234567", "success": true, "message_id": "def456", "parts": 1 }, { "to": "09191234567", "success": true, "message_id": "ghi789", "parts": 1 } ] } ``` | Field | Type | Description | |-------|------|-------------| | `success` | bool | `true` only if all destinations were sent successfully. | | `total` | int | Total number of destinations in the request. | | `sent` | int | Number of messages successfully sent. | | `failed` | int | Number of messages that failed. | | `results` | array | Per-destination result. Each entry includes `to`, `success`, and on success: `message_id` and `parts`. On failure: `error`. | **Note:** The HTTP status is always `200` when the request itself is valid, even if some individual sends failed. Check `success` and `failed` in the response body to detect partial failures. #### Error Response (request-level) — `402`, `400`, `403` Request-level errors (invalid input, insufficient credits, bad sender ID) return a flat error response — no `results` array: ```json { "success": false, "error": "insufficient credits: need 6, have 3" } ``` --- ### 3. Send OTP **`POST /api/otp/send`** Sends an OTP (One-Time Password) message. Identical to the SMS endpoint but routed through a dedicated OTP gateway. #### Request Headers Same as [Send SMS](#1-send-sms). #### Request Body Same as [Send SMS](#1-send-sms). #### Success Response Same as [Send SMS](#1-send-sms). --- ### 4. Send SIM **`POST /api/sim/send`** Sends a message via a SIM gateway (SMPP-to-SIM). Same request and response shape as Send SMS, but routed through the SIM pool. > **Account requirement:** The `sim` channel must be explicitly enabled on your account. Accounts default to SMS and OTP only. Contact Cast to enable SIM access. #### Request Headers Same as [Send SMS](#1-send-sms). #### Request Body Same as [Send SMS](#1-send-sms). #### Success Response Same as [Send SMS](#1-send-sms). #### Additional Error Responses | Status | Error | Cause | |--------|-------|-------| | `403 Forbidden` | `"sim channel not enabled for this account"` | Your account does not have SIM access | | `503 Service Unavailable` | `"sim service is disabled"` | The SIM gateway is not configured on the platform | --- ### 5. Send Bulk SIM **`POST /api/sim/bulk`** Sends the same message to multiple recipients via the SIM gateway. Identical to [Send Bulk SMS](#2-send-bulk-sms) in behavior and response shape, but routed through the SIM pool. > **Account requirement:** Same as [Send SIM](#4-send-sim) — the `sim` channel must be enabled on your account. #### Request Headers Same as [Send SMS](#1-send-sms). #### Request Body Same as [Send Bulk SMS](#2-send-bulk-sms). #### Success Response Same as [Send Bulk SMS](#2-send-bulk-sms). #### Additional Error Responses | Status | Error | Cause | |--------|-------|-------| | `403 Forbidden` | `"sim channel not enabled for this account"` | Your account does not have SIM access | | `503 Service Unavailable` | `"sim service is disabled"` | The SIM gateway is not configured on the platform | --- ## Error Handling All errors return a JSON body in this format: ```json { "success": false, "error": "error message here" } ``` ### HTTP Status Codes | Status Code | Meaning | |-------------|---------| | `200 OK` | Request succeeded | | `400 Bad Request` | Invalid or missing request fields | | `401 Unauthorized` | Missing or invalid API key | | `402 Payment Required` | Insufficient credits | | `403 Forbidden` | Access denied (see below) | | `429 Too Many Requests` | Rate limit exceeded | | `500 Internal Server Error` | Unexpected server error | | `503 Service Unavailable` | SMS/SIM service is temporarily disabled | ### Common Error Messages | Error Message | Status | Cause | |---------------|--------|-------| | `"missing X-API-Key header"` | 401 | No API key provided | | `"invalid api key"` | 401 | API key not found or invalid | | `"api key is revoked"` | 403 | API key has been deactivated | | `"api key has expired"` | 403 | API key passed its expiration date | | `"user account is inactive"` | 403 | Account has been disabled | | `"ip not whitelisted"` | 403 | Request origin IP is not in the allowed list | | `"sim channel not enabled for this account"` | 403 | SIM access is not enabled on your account | | `"insufficient credits: need X, have Y"` | 402 | Not enough credits to send the message | | `"no sender IDs assigned to this user"` | 403 | No sender ID has been configured for your account | | `"sender_id 'X' is not allowed for this user"` | 403 | The specified sender ID is not approved for your account | | `"to is required"` | 400 | The `to` field is missing | | `"to must be 7-15 characters"` | 400 | Phone number is not a valid length | | `"message is required"` | 400 | The `message` field is missing | | `"message is too long (max 450 characters)"` | 400 | Message exceeds the 3-part SMS limit | | `"sender ID is too long (max 11 characters)"` | 400 | Sender ID exceeds the character limit | --- ## Rate Limits | Limit | Value | |-------|-------| | Requests per second | 30 | | Burst (max simultaneous) | 50 | When you exceed the rate limit, the API returns `429 Too Many Requests` with a `Retry-After: 60` header. Wait the specified number of seconds before retrying. --- ## SMS Parts & Credits SMS messages are divided into **parts** based on length: | Encoding | Single SMS | Multi-part SMS (per part) | |----------|-----------|--------------------------| | GSM-7 (standard characters) | 160 chars | 153 chars | | Unicode (special characters, emoji) | 70 chars | 67 chars | Credits are deducted **per part** after the message is successfully sent. For example, a 200-character standard message uses 2 parts and costs 2 credits. --- ## IP Whitelisting If your account has IP whitelisting enabled, only requests from approved IP addresses or CIDR ranges will be accepted. Requests from unlisted IPs will receive a `403 Forbidden` response. Contact Cast to add or update your whitelisted IPs. --- ## Sender ID A Sender ID is the name or number displayed as the sender on the recipient's device (e.g., `MYAPP`, `BANK`, `639171234567`). - Sender IDs must be **pre-approved** before use. - If your account has only one Sender ID, the `sender_id` field in the request is optional — it will be used automatically. - If your account has multiple Sender IDs, you **must** specify the `sender_id` in each request. Contact Cast to register a Sender ID. --- ## Code Examples ### cURL — Bulk SMS ```bash curl -X POST https://api.cast.ph/api/sms/bulk \ -H "X-API-Key: cast_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "to": ["09171234567", "09181234567"], "message": "Hello from Cast!", "sender_id": "MYAPP" }' ``` ### cURL — Single SMS ```bash curl -X POST https://api.cast.ph/api/sms/send \ -H "X-API-Key: cast_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "to": "09171234567", "message": "Your verification code is 123456.", "sender_id": "MYAPP" }' ``` ### JavaScript (fetch) ```js const response = await fetch("https://api.cast.ph/api/sms/send", { method: "POST", headers: { "X-API-Key": "cast_your_api_key_here", "Content-Type": "application/json", }, body: JSON.stringify({ to: "639171234567", message: "Your verification code is 123456.", sender_id: "MYAPP", }), }); const data = await response.json(); if (data.success) { console.log("Sent! Message ID:", data.message_id, "Parts:", data.parts); } else { console.error("Failed:", data.error); } ``` ### Python (requests) ```python import requests response = requests.post( "https://api.cast.ph/api/sms/send", headers={ "X-API-Key": "cast_your_api_key_here", "Content-Type": "application/json", }, json={ "to": "09171234567", "message": "Your verification code is 123456.", "sender_id": "MYAPP", }, ) data = response.json() if data["success"]: print(f"Sent! Message ID: {data['message_id']}, Parts: {data['parts']}") else: print(f"Failed: {data['error']}") ``` ### PHP (cURL) ```php "639171234567", "message" => "Your verification code is 123456.", "sender_id" => "MYAPP", ]); $ch = curl_init("https://api.cast.ph/api/sms/send"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-API-Key: $apiKey", "Content-Type: application/json", ]); $response = json_decode(curl_exec($ch), true); curl_close($ch); if ($response["success"]) { echo "Sent! Message ID: " . $response["message_id"] . "\n"; } else { echo "Failed: " . $response["error"] . "\n"; } ``` ### C# (HttpClient) ```csharp using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Text.Json; var client = new HttpClient(); client.DefaultRequestHeaders.Add("X-API-Key", "cast_your_api_key_here"); var payload = JsonSerializer.Serialize(new { to = "09171234567", message = "Your verification code is 123456.", sender_id = "MYAPP" }); var content = new StringContent(payload, Encoding.UTF8, "application/json"); var response = await client.PostAsync("https://api.cast.ph/api/sms/send", content); var body = await response.Content.ReadAsStringAsync(); using var doc = JsonDocument.Parse(body); var root = doc.RootElement; if (root.GetProperty("success").GetBoolean()) { Console.WriteLine($"Sent! Message ID: {root.GetProperty("message_id").GetString()}, Parts: {root.GetProperty("parts").GetInt32()}"); } else { Console.WriteLine($"Failed: {root.GetProperty("error").GetString()}"); } ``` --- ## Support For API access, sender ID registration, IP whitelisting, or any technical issues, contact the Cast team.