Webhook SMS API
The Webhook SMS integration allows you to receive inbound SMS/MMS messages via HTTP webhooks and send outbound SMS through a simple REST API. This supports two-way messaging with AI platforms, automation tools, and custom applications.
How it works:
- A customer sends an SMS/MMS to your provisioned DID
- Our system forwards the message as a JSON POST to your configured webhook URL
- Your service can reply immediately in the HTTP response (synchronous reply)
- Your service can also send outbound SMS at any time via the outbound API endpoint (asynchronous)
Base URL
All API endpoints are served from:
https://api.cloudspirevoice.com/
Receiving Inbound SMS
When a customer sends an SMS or MMS to your DID, your webhook endpoint receives an HTTP POST with a JSON payload.
Request Details
| Property | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| Authorization | Value of your configured Auth Header (if set), otherwise omitted |
| Timeout | 30 seconds |
Inbound Payload
{
"event": "sms.inbound",
"from": "+17705551234",
"to": "+14045559999",
"text": "Hello, I need help with my account",
"media": [
"https://api.cloudspirevoice.com/uploads/wh_67ae1b2f3c4d5.jpg"
],
"timestamp": "2026-02-13T14:30:00-05:00"
}
Payload Fields
| Field | Type | Always Present | Description |
|---|---|---|---|
event | string | Yes | Always "sms.inbound" |
from | string | Yes | The sender's phone number in E.164 format (+1XXXXXXXXXX) |
to | string | Yes | Your DID that received the message, in E.164 format |
text | string | Yes | The message body. May be an empty string for MMS-only messages. |
media | array | No | Array of publicly accessible URLs for MMS attachments. Only present when the message includes media. Files are hosted on our server and retained for 30 days. |
timestamp | string | Yes | ISO 8601 timestamp with timezone offset |
Expected Response
Your endpoint must return an HTTP status in the 2xx range to confirm receipt. Any non-2xx response is treated as a delivery failure.
Fire-and-Forget (No Reply)
Return HTTP 200 with an empty body or any body without a reply field. The message is delivered to your system and no reply is sent to the customer.
Synchronous Reply
To send an immediate SMS reply back to the customer, return a JSON response with a reply field:
{
"reply": "Thanks for reaching out! Your account number is 12345.",
"media": ["https://example.com/receipt.pdf"]
}
| Field | Type | Required | Description |
|---|---|---|---|
reply | string | Yes | The SMS text to send back to the customer. Must be non-empty. |
media | array | No | Array of publicly accessible media URLs to include as MMS attachments. |
If the reply field is missing or empty, no reply is sent.
Sending Outbound SMS (Asynchronous)
Use this endpoint when your service needs to send an SMS outside of the synchronous reply window — for example, sending a follow-up message minutes or hours later, or initiating a new conversation.
Endpoint
POST https://api.cloudspirevoice.com/webhook-to-sms.php
Headers
| Header | Value |
|---|---|
Content-Type | application/json |
Request Payload
{
"from": "14045559999",
"to": "17705551234",
"text": "Your appointment is confirmed for Friday at 3pm.",
"secret": "your-webhook-secret",
"media_url": "https://example.com/confirmation.jpg"
}
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | The DID to send from (your provisioned number). Digits only, no + prefix. Must be a DID configured with WEBHOOK destination. |
to | string | Yes | The recipient phone number. Digits only, no + prefix. 10–15 digits. |
text | string | Conditional | The message body. Required unless media_url is provided. |
secret | string | Yes | The webhook secret configured for this DID. Must match exactly. |
media_url | string | No | A publicly accessible URL for an MMS attachment (image, PDF, etc.). When provided, the message is sent as MMS. If media_url is provided, text may be empty. |
Success Response
HTTP 200
{
"status": "success",
"message": "SMS Queued | FROM: 14045559999 | TO: 17705551234 | ID: bw-msg-abc123"
}
The ID value is the carrier message ID and can be used for delivery tracking.
Error Response
HTTP 400
{
"status": "error",
"message": "Authentication failed: invalid secret. Error: [WH-AUTH]"
}
Error Codes
| Code | Meaning | Resolution |
|---|---|---|
[WH-AUTH] | Secret is missing or does not match | Verify the secret value matches the Webhook Secret provided to you by your onCloud administrator |
[WH-1] | Missing required fields or invalid JSON | Ensure from, to, and either text or media_url are present in a valid JSON body |
[WH-2] | Phone number format invalid | Use 10–15 digit format, digits only (e.g., 14045559999, not +1-404-555-9999) |
[WH-3] | DID not configured for webhook | The from number must be provisioned for webhook SMS by your onCloud administrator |
[WH-23-2] | No active SMS plan for this DID | Contact your onCloud administrator to verify the DID has an active SMS plan |
[WH-23-3] | Monthly SMS limit exceeded | The plan's monthly message limit has been reached. Contact your administrator to increase the limit or wait for the next billing cycle. |
[WH-23-4] | Plan does not include outbound | The SMS plan for this DID does not include outbound messages. Contact your administrator. |
Complete Two-Way Example
This example demonstrates a typical two-way SMS flow using n8n as middleware between your DID and an AI service.
Step 1: Your Endpoint Receives Inbound SMS
When a customer texts your DID, your webhook endpoint receives:
{
"event": "sms.inbound",
"from": "+17705551234",
"to": "+14045559999",
"text": "What are your business hours?",
"timestamp": "2026-02-13T14:30:00-05:00"
}
Step 2: Send a Synchronous Reply
If your service can generate a reply within 30 seconds (e.g., a quick AI lookup), respond directly in the HTTP response body:
{
"reply": "Our business hours are Monday-Friday 9am-5pm EST. Can I help with anything else?"
}
The system automatically sends this as an SMS from your DID to the customer.
Step 3: Send an Async Follow-Up
If your service needs to send a message later (a follow-up, a scheduled reminder, or any message outside the 30-second window), POST to the outbound endpoint:
curl -X POST https://api.cloudspirevoice.com/webhook-to-sms.php \
-H "Content-Type: application/json" \
-d '{
"from": "14045559999",
"to": "17705551234",
"text": "Just following up - did you need anything else?",
"secret": "your-webhook-secret"
}'
Phone Number Format Reference
| Context | Format | Example |
|---|---|---|
Inbound payload (from, to) | E.164 with + | +14045559999 |
Outbound request (from, to) | Digits only, no + | 14045559999 |
All phone numbers must include the country code (e.g., 1 for US/Canada).
Billing and Limits
- Both inbound webhook deliveries and outbound SMS count against your DID's monthly message limit
- Synchronous replies sent from webhook responses also count toward the limit
- When the limit is reached, outbound sends return error
[WH-23-3]. Inbound messages are still delivered to your webhook, but automatic replies will fail. - Usage resets on the 1st of each month
Media / MMS Notes
- Inbound MMS attachments are downloaded from the carrier and re-hosted at
https://api.cloudspirevoice.com/uploads/ - Hosted media files are automatically cleaned up after 30 days
- For outbound MMS, the
media_urlmust be a publicly accessible HTTP or HTTPS URL - If an invalid
media_urlis provided on outbound, the message is sent as SMS only (the media is silently dropped)