Developer reference
Swift Inbox API
Send WhatsApp messages, manage templates, and embed the Swift Inbox UI inside your CRM. All
endpoints live under
https://www.swiftinbox.in/api/v1
and authenticate with a Sanctum API key (issued from Manage → Integrate → API keys).
https://www.swiftinbox.in/api/v1
- Authorization: Bearer <api-key>
- X-API-Key: <api-key>
AI Integration Assistant
Step of 5 ·
Which AI coding assistant will build this for you?
We will format prompt headers, instructions, and system task wrappers specifically for this tool.
What WhatsApp features do you want to integrate?
Select all modules that apply. The prompt will configure service methods for each.
What is your project's technology stack?
The AI coding tool will generate idiomatically correct service wrappers, config files, and tests.
Templates & Credentials Setup
Customise your project name and specify which templates you need mapped.
Your AI Integration Prompt is Ready!
Paste this prompt directly into Antigravity or Cursor in your project repository.
Getting started
- Sign in to Swift Inbox and open Manage → Integrate → API keys.
- Create a key with the abilities you need (e.g.
messages:send,templates:read). The plaintext token is shown once — copy it immediately. - Make a sanity call to GET /me to confirm the key + abilities.
- Send your first message with POST /messages/template.
Authentication
Every request must carry an API key in either of these headers (use whichever your HTTP client prefers — they're equivalent):
Authorization: Bearer wabt_xxxxxxxxxxxxxxxxxxxxxxxx
X-API-Key: wabt_xxxxxxxxxxxxxxxxxxxxxxxx
Each key is scoped to a single merchant and a fixed set of abilities (Sanctum
scopes). Calling an endpoint with a key that's missing the required ability returns 403
forbidden. Keys can be revoked at any time from the integration panel; revocation is
immediate.
Response envelope
Every /api/v1/* response is wrapped in a consistent envelope. Branch on
code (numeric, mirrors the HTTP status) or the HTTP status itself — both will always
agree.
{
"code": 200,
"data": { … },
"message": "OK"
}
{
"code": 422,
"data": null,
"error": "validation_failed",
"message": "The body field is required.",
"errors": {
"body": ["The body field is required."]
}
}
On errors, data is always null and a top-level error slug
identifies the failure class. Field-level validation errors are surfaced as a top-level
errors map (Laravel-conventional shape). Subscription-blocked responses additionally
include a pay_now URL.
Error codes
The error slug returned in the envelope identifies the failure cleanly without parsing
the prose message. Common values across endpoints:
| HTTP | Error slug | When |
|---|---|---|
| 400 | bad_request | Malformed request (e.g. invalid JSON body). |
| 401 | unauthenticated | Missing, malformed, or revoked API key. |
| 403 | forbidden | Key is valid but missing the required ability for this endpoint. |
| 404 | not_found | The referenced resource (template id, etc.) does not exist on this merchant. |
| 409 | conflict | The mutation conflicts with current state (e.g. duplicate template name+language). |
| 422 | validation_failed | Request body / query failed validation. Includes errors map.
|
| 422 | invalid_variables | Template variables don't match the template definition. |
| 402 | subscription_blocked | Merchant's annual platform fee is unpaid. Response includes pay_now.
|
| 429 | too_many_requests | Rate limit exceeded; retry with backoff. |
| 500 | server_error | Unhandled exception inside Swift Inbox. Logged with a correlation id; safe to retry. |
A handful of domain-specific errors (SessionWindowClosedException,
WabaNotConnectedException, InsufficientWalletBalanceException) surface
their class basename as error rather than a slug — these are documented inline per
endpoint below.
Outbound Webhooks
Configure real-time webhooks under Settings → Developer & Webhook Settings to receive instant HTTP POST callbacks when message statuses update or inbound button replies occur.
Supported Event Types
| Event | Description |
|---|---|
| msg_received | Fired when an inbound text or media message is received. |
| msg_sent | Fired when an outbound message is queued and dispatched to Meta. |
| msg_delivered | Fired when Meta confirms message delivery to the recipient's phone. |
| msg_read | Fired when the recipient opens and reads the WhatsApp message. |
| msg_failed | Fired when message delivery fails due to invalid recipient or Meta error. |
| msg_skipped | Fired when a message is skipped because the recipient's WhatsApp availability probability score falls below the configured threshold. |
| button_reply | Fired when an inbound quick-reply or button response is received. |
HMAC Signature Verification
When a secret is configured, every HTTP POST request contains the X-AppRinger-Signature header
computed via HMAC SHA-256 over the raw JSON payload:
$signature = hash_hmac('sha256', $rawBody, $webhookSecret);
Sample Payloads by Event
{
"event": "msg_received",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM5...",
"from": "+919876543210",
"recipient": "+919717146603",
"type": "text",
"text": "Hello, I want to order something",
"body": "Hello, I want to order something",
"media_mime": null,
"raw_payload": { ... },
"timestamp": "2026-08-01T08:52:00+00:00"
}
{
"event": "msg_skipped",
"msg_id": "MSG_CUSTOM_001",
"camp_id": "CAMP_AUGUST_01",
"client_reference": "order-1234",
"wa_message_id": null,
"status": "skipped_low_probability",
"recipient": "+919876543210",
"template_name": "welcome_alert",
"wa_probability_score": {
"phone": "+919876543210",
"delivery_probability": 15.4,
"read_probability": 8.2,
"risk_level": "high",
"data_points": 142
},
"timestamp": "2026-08-01T08:50:00+00:00"
}
{
"event": "msg_sent",
"msg_id": "MSG_CUSTOM_001",
"camp_id": "CAMP_AUGUST_01",
"client_reference": "order-1234",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM4...",
"status": "sent",
"recipient": "+919876543210",
"timestamp": "2026-08-01T08:50:00+00:00"
}
{
"event": "msg_delivered",
"msg_id": "MSG_CUSTOM_001",
"camp_id": "CAMP_AUGUST_01",
"client_reference": "order-1234",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM4...",
"status": "delivered",
"recipient": "+919876543210",
"timestamp": "2026-08-01T08:50:02+00:00"
}
{
"event": "msg_read",
"msg_id": "MSG_CUSTOM_001",
"camp_id": "CAMP_AUGUST_01",
"client_reference": "order-1234",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM4...",
"status": "read",
"recipient": "+919876543210",
"timestamp": "2026-08-01T08:51:15+00:00"
}
{
"event": "msg_failed",
"msg_id": "MSG_CUSTOM_001",
"camp_id": "CAMP_AUGUST_01",
"client_reference": "order-1234",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM4...",
"status": "failed",
"recipient": "+919876543210",
"error_code": "131026",
"error_title": "Undeliverable",
"error_message": "Unable to deliver message to recipient number",
"timestamp": "2026-08-01T08:50:05+00:00"
}
{
"event": "button_reply",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM5...",
"from": "+919876543210",
"recipient": "+919717146603",
"body": "Confirm Order",
"button_reply": {
"title": "Confirm Order",
"id": "BTN_CONFIRM_123",
"payload": "BTN_CONFIRM_123"
},
"timestamp": "2026-08-01T08:52:00+00:00"
}
List campaigns
Returns a paginated list of campaigns for the merchant.
curl -X GET 'https://www.swiftinbox.in/api/v1/campaigns' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": [],
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
Create a campaign
Creates a new campaign for the merchant.
Request body
| Field | Type | Description |
|---|---|---|
|
name
required
|
string
|
Campaign name. |
|
template_id
required
|
integer
|
Template to use. |
curl -X POST 'https://www.swiftinbox.in/api/v1/campaigns' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"name": "August Promo", "template_id": 42}'
Response · 201
{
"code": 201,
"data": {
"uuid": "cam_abc123"
},
"message": "Created"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 422 | validation_failed | Required fields missing or invalid. |
Get campaign details
Returns details of a specific campaign.
curl -X GET 'https://www.swiftinbox.in/api/v1/campaigns/cam_abc123' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"uuid": "cam_abc123",
"status": "draft"
},
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 404 | not_found | Campaign not found. |
Launch a campaign
Starts sending a campaign.
curl -X POST 'https://www.swiftinbox.in/api/v1/campaigns/cam_abc123/launch' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"status": "running"
},
"message": "Launched"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 409 | conflict | Campaign is not in a launchable state. |
Pause a running campaign
Pauses a running campaign. Resume later with the resume endpoint.
curl -X POST 'https://www.swiftinbox.in/api/v1/campaigns/cam_abc123/pause' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"status": "paused"
},
"message": "Paused"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 409 | conflict | Campaign is not running. |
Resume a paused campaign
Resumes a previously paused campaign.
curl -X POST 'https://www.swiftinbox.in/api/v1/campaigns/cam_abc123/resume' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"status": "running"
},
"message": "Resumed"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 409 | conflict | Campaign is not paused. |
Adjust campaign send speed
Changes the send speed (messages per second) of a running campaign.
Request body
| Field | Type | Description |
|---|---|---|
|
speed
required
|
integer
|
Messages per second. |
curl -X POST 'https://www.swiftinbox.in/api/v1/campaigns/cam_abc123/speed' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"speed": 10}'
Response · 200
{
"code": 200,
"data": {
"speed": 10
},
"message": "Speed updated"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 422 | validation_failed | Speed value out of allowed range. |
List contacts
Returns a paginated list of contacts for the merchant.
curl -X GET 'https://www.swiftinbox.in/api/v1/contacts' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": [],
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
Create a contact
Creates or upserts a contact for the merchant.
Request body
| Field | Type | Description |
|---|---|---|
|
phone
required
|
string
|
E.164 phone number. |
|
name
optional
|
string
|
Contact display name. |
curl -X POST 'https://www.swiftinbox.in/api/v1/contacts' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"phone": "919876543210", "name": "Riya"}'
Response · 201
{
"code": 201,
"data": {
"id": 1,
"phone": "+919876543210"
},
"message": "Created"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 422 | validation_failed | Required fields missing or invalid. |
Get contact details
Returns details of a specific contact.
curl -X GET 'https://www.swiftinbox.in/api/v1/contacts/42' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"id": 42,
"phone": "+919876543210"
},
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 404 | not_found | Contact not found. |
Sanity-check the API key
Returns the owning user, their merchant account and the abilities granted to the token. Hit this first after issuing a key to confirm credentials are wired up correctly.
curl -X GET 'https://www.swiftinbox.in/api/v1/me' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"user": {
"id": 1,
"name": "Riya Singh",
"email": "riya@acme.test",
"role": "merchant_admin"
},
"merchant": {
"id": 1,
"name": "Acme Pvt Ltd",
"slug": "acme"
},
"token": {
"name": "crm-prod",
"abilities": [
"messages:send",
"templates:read"
]
}
},
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing, malformed, or revoked API key. |
Check the prepaid balance
Returns the current wallet balance, the configured low-balance threshold, and the per-message rates this merchant pays. Useful for surfacing a top-up nag inside your own dashboard before a send fails with InsufficientWalletBalanceException.
curl -X GET 'https://www.swiftinbox.in/api/v1/wallet/balance' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"merchant": {
"id": 1,
"slug": "acme"
},
"currency": "INR",
"balance": "1000.00",
"low_balance_threshold": "500.00",
"is_low_balance": false,
"rates": {
"session": "0.50",
"utility": "0.60",
"marketing": "1.20",
"authentication": "0.40",
"text": "0.50",
"template": "0.60"
}
},
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key is missing the wallet:read ability. |
| 402 | subscription_blocked |
Annual platform fee unpaid. Response includes pay_now URL. |
Send a session (free-form) text message
Sends a plaintext WhatsApp message. Only allowed inside the 24-hour customer service window (i.e. the recipient must have messaged you in the last 24 hours). Use POST /messages/template to re-engage outside the window.
Request body
| Field | Type | Description |
|---|---|---|
|
to
required
|
string
|
E.164 recipient phone, no leading +. Required unless conversation_id is supplied. 5–32 chars. |
|
body
required
|
string
|
Message text. 1–4096 chars. |
|
conversation_id
optional
|
integer
|
Swift Inbox conversation id. When set, the recipient + phone are inferred from the conversation and to can be omitted. |
|
phone_number_id
optional
|
integer
|
Swift Inbox phone-number row id. Send from a specific number when the merchant has multiple connected numbers. Defaults to the merchant's default number. |
|
client_reference
optional
|
string
|
Your idempotency key / order id. Echoed back on the response and on every status webhook. ≤64 chars. |
|
msg_id
optional
|
string
|
Your custom message ID. Echoed back on status responses, status webhooks, and queryable via GET /messages/status/{msgId}. ≤128 chars. |
|
camp_id
optional
|
string
|
Campaign identifier for tracking campaign performance across webhooks. ≤128 chars. |
curl -X POST 'https://www.swiftinbox.in/api/v1/messages/text' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "919876543210",
"body": "Hi, your order #1234 has shipped.",
"client_reference": "order-1234"
}'
Response · 202
{
"code": 202,
"data": {
"id": 42,
"status": "queued",
"client_reference": "order-1234",
"wa_message_id": null,
"billed_amount": "0.5000",
"currency": "INR"
},
"message": "Accepted"
}
status starts at queued and progresses to sent / delivered / read as Meta acknowledges. Occasionally Meta acks within the same request and you'll see sent already in this response. billed_amount is a decimal string (4 d.p.); wa_message_id is filled once Meta returns it (poll id if you need it synchronously).
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key is missing the messages:send ability. |
| 422 | validation_failed |
Required field missing or malformed. Response includes errors: { field: [messages] }. |
| 422 | SessionWindowClosedException | Recipient has not messaged you in the last 24h. Send a template instead. |
| 402 | InsufficientWalletBalanceException |
Wallet balance is below the cost of this send. Top up at the URL in pay_now. |
| 409 | WabaNotConnectedException |
Merchant has no connected WhatsApp number. Complete the registration wizard in the Swift Inbox dashboard. |
| 402 | subscription_blocked | Annual platform fee unpaid. |
Send an approved template message
Send one of your approved templates. Use this for any first-touch / re-engagement send outside the 24-hour session window — order confirmations, shipping updates, marketing nudges, OTPs. Pass either template_id (preferred — copy it from WhatsApp settings → Templates) or the template_name+language pair.
Authentication (OTP) Templates:
For authentication templates with a Copy Code or One-Tap Autofill button, you must supply the OTP code twice in the API request: once for the message body and once for the button. You can do this easily using the simplified variables and button_variables fields, or via raw components.
Example using variables:
{
"to": "919876543210",
"template_name": "otp_verification",
"language": "en_US",
"variables": {"1": "123456"},
"button_variables": ["123456"]
}
Request body
| Field | Type | Description |
|---|---|---|
|
to
required
|
string
|
E.164 recipient phone, no leading +. Required unless conversation_id is supplied. |
|
template_id
conditional
|
integer
|
Swift Inbox template id. Required unless template_name + language are supplied. Copy it from the API id chip next to each template in the dashboard. |
|
template_name
conditional
|
string
|
Template name as registered with Meta. Required when template_id is omitted. |
|
language
conditional
|
string
|
BCP-47 language tag (e.g. en_US). Required when template_id is omitted. |
|
variables
optional
|
object
|
Positional map for {{1}}, {{2}}… in the body. We build Meta's components for you. Keys can be "1", "2"… or named (when your template defines named params). |
|
header_variables
optional
|
array
|
Values for header placeholders, in order. |
|
button_variables
optional
|
array
|
Values for URL-button or OTP/Authentication button (Copy Code / One-Tap) placeholders, in order. |
|
components
optional
|
array
|
Raw Meta-shape components array. Power-user escape hatch — wins over variables if both are sent. Use this when a header carries a media asset. |
|
conversation_id
optional
|
integer
|
Swift Inbox conversation id. Optional alternative to to. |
|
phone_number_id
optional
|
integer
|
Send from a specific number. Defaults to the merchant's default. |
|
client_reference
optional
|
string
|
Your idempotency key / order id. Echoed back on the response and on every status webhook. |
|
msg_id
optional
|
string
|
Your custom message ID. Echoed back on status responses, status webhooks, and queryable via GET /messages/status/{msgId}. ≤128 chars. |
|
camp_id
optional
|
string
|
Campaign identifier for tracking campaign performance across webhooks. ≤128 chars. |
curl -X POST 'https://www.swiftinbox.in/api/v1/messages/template' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "919876543210",
"template_id": 42,
"variables": {
"1": "Riya",
"2": "A-12"
},
"client_reference": "order-1234"
}'
Response · 202
{
"code": 202,
"data": {
"id": 43,
"status": "sent",
"client_reference": "order-1234",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM4FQIAERgSMUQ3...",
"billed_amount": "0.6000",
"currency": "INR",
"template_name": "order_confirmation"
},
"message": "Accepted"
}
Identical envelope to /messages/text plus a template_name field for traceability. status is usually queued; if Meta acks before this response returns you may see sent directly. wa_message_id is filled once Meta returns the WAMID.
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key missing messages:send. |
| 404 | not_found |
Template id / name+language doesn't match any template on this merchant. Run GET /templates to list what's available. |
| 422 | validation_failed | Required field missing or malformed. |
| 422 | invalid_variables |
The variables map doesn't match what the template definition expects. |
| 402 | InsufficientWalletBalanceException | Wallet too low for the per-template rate. |
| 409 | WabaNotConnectedException |
No connected WhatsApp number on this merchant. |
| 402 | subscription_blocked | Annual platform fee unpaid. |
Send a template message in bulk
Send an approved template to multiple recipients in one request. Useful for broadcasts and large campaigns.
Request body
| Field | Type | Description |
|---|---|---|
|
template_id
optional
|
integer
|
Swift Inbox template id. |
|
template_name
optional
|
string
|
Template name as registered with Meta. |
|
language
optional
|
string
|
BCP-47 language tag. |
|
phone_number_id
optional
|
integer
|
Send from a specific number. Defaults to the merchant's default. |
|
recipients
required
|
array
|
List of recipient objects (up to 10000). |
|
recipients[].to
required
|
string
|
E.164 recipient phone. |
|
recipients[].variables
optional
|
object
|
Variables for this recipient. |
curl -X POST 'https://www.swiftinbox.in/api/v1/messages/bulk-template' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"template_id": 42,
"recipients": [
{
"to": "919876543210",
"variables": { "1": "Riya" },
"client_reference": "order-1"
}
]
}'
Response · 202
{
"message": "Bulk message queued successfully.",
"queued_count": 1
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key missing messages:send ability. |
| 422 | validation_failed | Required field missing or malformed. |
Check delivery status by msg_id
Query the current delivery status of a message using your custom msg_id, Meta's wa_message_id, or client_reference. Returns delivery timestamps and error details if the send failed.
curl -X GET 'https://www.swiftinbox.in/api/v1/messages/status/MSG_12345' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"id": 42,
"msg_id": "MSG_12345",
"camp_id": "CAMP_6789",
"client_reference": "order-1234",
"wa_message_id": "wamid.HBgMOTE4MTQzOTU2NDM4...",
"recipient": "+919876543210",
"status": "delivered",
"sent_at": "2026-08-01T08:50:00+00:00",
"delivered_at": "2026-08-01T08:50:02+00:00",
"read_at": null,
"failed_at": null,
"error_code": null,
"error_title": null,
"error_message": null,
"billed_amount": "0.5000",
"currency": "INR"
},
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key missing messages:send ability. |
| 404 | not_found |
Message with the given msg_id not found. |
List your WhatsApp senders
Discovery endpoint for the phone_number_id you can pass to POST /messages/text and POST /messages/template when routing through a specific sender on a multi-line merchant. Omit phone_number_id on the send endpoints and we'll use the row flagged is_default: true here.
Query parameters
| Field | Type | Description |
|---|---|---|
|
status
optional
|
string
|
Filter by phone state. One of connected (default), pending, disconnected, or all. Only connected rows are valid as phone_number_id on the send endpoints; ?status=all is for auditing why a number disappeared. |
curl -X GET 'https://www.swiftinbox.in/api/v1/phone-numbers' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"data": [
{
"id": 7,
"display_phone_number": "+91 80 5555 5555",
"verified_name": "Acme Pvt Ltd",
"status": "connected",
"is_default": true,
"quality_rating": "GREEN"
},
{
"id": 12,
"display_phone_number": "+91 80 5555 7777",
"verified_name": "Acme Support",
"status": "connected",
"is_default": false,
"quality_rating": "GREEN"
}
],
"meta": {
"count": 2,
"status": "connected"
}
},
"message": "OK"
}
Rows are sorted with the default-flagged number first, then by id — same order as the picker on the dashboard. id is the value to pass as phone_number_id on the send endpoints; display_phone_number is for showing in your own UI.
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key is missing the messages:send ability. |
List your templates
Returns the catalog of templates registered on the merchant. By default a slim summary per row; pass ?detailed=true to also receive the full Meta-shape components + example blobs.
Tip: the API id chip next to each template in WhatsApp settings → Templates is the same id returned here — no need to hit this endpoint just to look up an id.
Query parameters
| Field | Type | Description |
|---|---|---|
|
category
optional
|
string
|
Filter by UTILITY, MARKETING, or AUTHENTICATION. |
|
status
optional
|
string
|
Filter by pending, approved, rejected, paused, disabled, or deleted. |
|
per_page
optional
|
integer
|
Page size, 1–200. Default 50. |
|
detailed
optional
|
boolean
|
Include full components + example blobs. Default false. |
curl -X GET 'https://www.swiftinbox.in/api/v1/templates?status=approved&category=UTILITY' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"code": 200,
"data": {
"data": [
{
"id": 3,
"name": "new_lead_collected",
"language": "en",
"category": "UTILITY",
"status": "approved",
"meta_template_id": "867792625617937",
"approved_at": "2026-05-20T08:34:00+00:00",
"body_preview": "🛎 New Lead Collected\nCustomer: *{{1}}*…",
"variables_count": 4,
"buttons_count": 0,
"has_header": false,
"has_footer": false
}
],
"meta": {
"page": 1,
"per_page": 50,
"total": 1,
"total_pages": 1
}
},
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key missing templates:read. |
| 422 | validation_failed |
Unknown category or status value, or per_page out of range. |
Register a new template for Meta review
Submits a draft template to Meta for review. Lands locally in pending status; Meta typically returns an approval within minutes and the row auto-flips to approved via webhook. Once approved, send it with POST /messages/template.
Request body
| Field | Type | Description |
|---|---|---|
|
name
required
|
string
|
Snake_case template id, max 128 chars. Must match /^[a-z0-9_]+$/i. Must be unique per language. |
|
language
required
|
string
|
BCP-47 language tag, e.g. en_US, hi, mr. |
|
category
required
|
string
|
One of UTILITY (transactional), MARKETING (promotional), AUTHENTICATION (OTP). |
|
components
required
|
array
|
Meta-shape components array. At minimum a BODY component with text. Use {{1}}, {{2}}… for placeholders. |
|
example
optional
|
object
|
Sample values Meta uses while reviewing. Required for templates with placeholders, e.g. { "body_text": [["Riya", "A-12"]] }. |
curl -X POST 'https://www.swiftinbox.in/api/v1/templates' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"name": "order_confirmation",
"language": "en_US",
"category": "UTILITY",
"components": [
{ "type": "BODY", "text": "Hi {{1}}, your order {{2}} is confirmed." }
],
"example": { "body_text": [["Riya", "A-12"]] }
}'
Response · 201
{
"code": 201,
"data": {
"id": 5,
"name": "order_confirmation",
"language": "en_US",
"category": "UTILITY",
"status": "pending",
"meta_template_id": null,
"approved_at": null,
"components": [
{
"type": "BODY",
"text": "Hi {{1}}, your order {{2}} is confirmed."
}
],
"example": {
"body_text": [
[
"Riya",
"A-12"
]
]
}
},
"message": "Created"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key missing templates:write. |
| 422 | validation_failed | Malformed components, missing example for a placeholder template, etc. |
| 409 | conflict |
A template with the same name+language already exists on this merchant. |
Delete a template
Deletes a template. Note that this only removes the template from Swift Inbox; you must still delete it in the Meta Business Manager.
curl -X DELETE 'https://www.swiftinbox.in/api/v1/templates/42' \
-H 'X-API-Key: YOUR_API_KEY'
Response · 200
{
"message": "Template deleted successfully."
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key missing templates:write. |
| 404 | not_found | Template not found for this merchant. |
Mint a JWT for embedded SSO (BETA)
BETA / Testing Feature: Server-to-server mint of a short-lived JWT for Iframe SSO embedding inside partner CRMs. Use the returned embed_url as an iframe src to drop the Swift Inbox UI inside your CRM with the targeted user already signed in. With auto_provision: true, the user is created on-the-fly if they don't exist yet.
Request body
| Field | Type | Description |
|---|---|---|
|
email
optional
|
string
|
Target user's email. Required unless user_id is supplied. |
|
user_id
optional
|
integer
|
Swift Inbox user id. Required unless email is supplied. |
|
ttl_seconds
optional
|
integer
|
Token lifetime, 60–86400 (24h). Default 300 (5 min). |
|
redirect_to
optional
|
string
|
Path inside Swift Inbox to land on. Must start with /. Defaults to /inbox. |
|
auto_provision
optional
|
boolean
|
Create the user if not found. Requires email + name + role. |
|
role
optional
|
string
|
When auto-provisioning: agent or manager. |
|
name
optional
|
string
|
When auto-provisioning: display name, max 120 chars. |
|
features
optional
|
array
|
When auto-provisioning: subset of ["inbox", "tasks"] to grant. |
curl -X POST 'https://www.swiftinbox.in/api/v1/iframe-tokens' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"email": "agent@acme.com",
"ttl_seconds": 300,
"redirect_to": "/inbox",
"auto_provision": true,
"role": "agent",
"features": ["inbox", "tasks"]
}'
Response · 200
{
"code": 200,
"data": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIsImV4cCI6MTczMjAwMDAwMH0.signature",
"expires_at": "2026-05-20T14:00:00+00:00",
"embed_url": "https://app.example.com/embed?token=eyJ0eXAi...",
"ttl_seconds": 300,
"user": {
"id": 2,
"email": "agent@acme.com",
"name": "Agent Two",
"role": "agent"
},
"provisioned": false
},
"message": "OK"
}
Errors
| HTTP | Error slug | When |
|---|---|---|
| 401 | unauthenticated | Missing or invalid API key. |
| 403 | forbidden |
Key missing iframe:mint or not merchant-scoped. |
| 404 | not_found |
User not found. Pass auto_provision: true + name + role to create them on the fly. |
| 422 | provision_failed |
Auto-provision validation failed. Response includes errors map. |
| 422 | user_inactive | Target user is disabled. |
| 422 | merchant_missing | API key's merchant row is missing (rare; usually a deleted merchant). |