Triggering API Campaigns¶
An API Campaign is a reusable messaging configuration created and managed in the Abelo CMS. It defines how a message should be sent, including the channel, sender, message template, category, and optional fallback settings.
Once an API Campaign is active, your application can trigger individual message dispatches programmatically through the Abelo REST API. Messages can be delivered through Viber Business Messages (with optional SMS fallback) or directly through SMS.
This guide explains how to configure an API Campaign and use it to send personalized, on-demand messages from backend applications, authentication services, e-commerce platforms, and other integrated systems.
1. Create and Activate an API Campaign in the CMS¶
Before triggering messages through the API, create and configure an API Campaign in the Abelo CMS:
- Navigate to Campaigns > API Campaigns > New Campaign in the Abelo CMS.
- Select the primary messaging channel: Viber Business Messages ( If Viber is selected, you can optionally enable SMS Fallback) or SMS
- Select the campaign category: OTP, Transactional, or Promotional
- Select a template & configure the delivery options
- Set the campaign status to Active.
- Copy the campaign's Public ID (e.g.
c-8Fa...).
2. API Request Specification¶
Endpoint: POST /v1/messages/send
Authentication: Authorization: Bearer <key_id>:<key_secret> (requires messages:send scope)
Content-Type: application/json
Request Body Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
campaign_id |
String | Yes | The secure public ID of an active API Campaign. |
recipient |
Object | Yes | The recipient identifier object (discriminated by type). |
recipient.type |
String | Yes | One of "phone_number", "email", or "public_id". |
recipient.value |
String | Yes | Recipient value: E.164 phone number (e.g. +306912345678), email, or public ID. |
params |
Object | Optional | Key-value dictionary providing values for all template placeholders. |
client_reference |
String | Optional | Custom identifier (e.g. order_98124, otp_sess_102) echoed back in response and webhooks. |
webhook_url |
String | Optional | Per-message webhook URL. If provided, all lifecycle events for this specific message are delivered to this URL and signed with your API key's webhook_signing_secret. |
3. Recipient Resolution & Consent Rules¶
| Campaign Category | Marketing Consent Required? | Profile Handling | Error if Ineligible |
|---|---|---|---|
| OTP | ❌ No | A Profile is created automatically if the phone number is not already associated with a Profile. | — |
| Transactional | ❌ No | A Profile is created automatically if the phone number is not already associated with a Profile. | — |
| Promotional | ✅ Yes | The recipient must already exist as a Profile and have active promotional consent for the channel being used. (viber_consent: true or sms_consent: true). |
403 Forbidden (Promotional consent not found for profile.) |
4. Code Examples¶
Example A: Send an OTP Verification Code¶
curl -X POST https://api.abelo.ai/v1/messages/send \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ak_01J8K92M4:as_9f8a7b6c5d4e3f2a1b0c" \
-d '{
"campaign_id": "cmp_01J8K92M4_OTP",
"recipient": {
"type": "phone_number",
"value": "+306912345678"
},
"params": {
"code": "582914"
},
"client_reference": "auth_req_8921"
}'
import httpx
AUTH_TOKEN = "ak_01J8K92M4:as_9f8a7b6c5d4e3f2a1b0c"
API_URL = "https://api.abelo.ai/v1/messages/send"
payload = {
"campaign_id": "cmp_01J8K92M4_OTP",
"recipient": {
"type": "phone_number",
"value": "+306912345678"
},
"params": {
"code": "582914"
},
"client_reference": "auth_req_8921"
}
response = httpx.post(
API_URL,
headers={
"Authorization": f"Bearer {AUTH_TOKEN}",
"Content-Type": "application/json"
},
json=payload
)
data = response.json()
print(f"Message Status: {data['status']}, ID: {data['message_id']}")
const AUTH_TOKEN = "ak_01J8K92M4:as_9f8a7b6c5d4e3f2a1b0c";
const API_URL = "https://api.abelo.ai/v1/messages/send";
async function sendOtp() {
const response = await fetch(API_URL, {
method: "POST",
headers: {
"Authorization": `Bearer ${AUTH_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
campaign_id: "cmp_01J8K92M4_OTP",
recipient: {
type: "phone_number",
value: "+306912345678"
},
params: {
code: "582914"
},
client_reference: "auth_req_8921"
})
});
const data = await response.json();
console.log("OTP Dispatch Response:", data);
}
sendOtp();
Example B: Send a Transactional Order Confirmation with Per-Message Webhook¶
curl -X POST https://api.abelo.ai/v1/messages/send \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ak_01J8K92M4:as_9f8a7b6c5d4e3f2a1b0c" \
-d '{
"campaign_id": "cmp_01J8K92M4_ORDER",
"recipient": {
"type": "phone_number",
"value": "+306912345678"
},
"params": {
"first_name": "Maria",
"order_number": "ORD-4921",
"tracking_url": "https://carrier.com/track/4921"
},
"client_reference": "order_4921",
"webhook_url": "https://api.myshop.com/webhooks/delivery"
}'
import httpx
AUTH_TOKEN = "ak_01J8K92M4:as_9f8a7b6c5d4e3f2a1b0c"
API_URL = "https://api.abelo.ai/v1/messages/send"
payload = {
"campaign_id": "cmp_01J8K92M4_ORDER",
"recipient": {
"type": "phone_number",
"value": "+306912345678"
},
"params": {
"first_name": "Maria",
"order_number": "ORD-4921",
"tracking_url": "https://carrier.com/track/4921"
},
"client_reference": "order_4921",
"webhook_url": "https://api.myshop.com/webhooks/delivery"
}
response = httpx.post(
API_URL,
headers={
"Authorization": f"Bearer {AUTH_TOKEN}",
"Content-Type": "application/json"
},
json=payload
)
print(response.status_code, response.json())
5. Response Structure & Status Codes¶
Successful Dispatch (200 OK)¶
{
"message_id": "0191636f-bcf0-7813-9f89-8d7681728271",
"status": "sent",
"client_reference": "auth_req_8921",
"error": null
}
Response Attributes¶
| Field | Type | Description |
|---|---|---|
message_id |
String | Unique UUID v7 identifier for the dispatched message. |
status |
String | Initial dispatch status ("sent" or "failed"). |
client_reference |
String / Null | The client reference provided in the request body. |
error |
Object / Null | Error details if upstream dispatch failed. |
HTTP Status Code Catalog¶
| Status Code | Description | Cause / Resolution |
|---|---|---|
200 OK |
Message dispatched successfully | Message submitted to upstream carrier or Viber network. |
400 Bad Request |
Invalid request parameters | Missing required template variable, campaign inactive, or ambiguous email lookup (multiple profiles match same email). |
401 Unauthorized |
Missing or invalid API key | API key invalid or expired. Verify Authorization: Bearer header. |
403 Forbidden |
Promotional consent missing | Campaign is Promotional, but the recipient has not opted in to marketing on this channel. |
404 Not Found |
Campaign or profile not found | Invalid campaign_id or recipient profile does not exist (for promotional campaigns). |
429 Too Many Requests |
Rate limit exceeded | Exceeded 100 requests per 60s window. Inspect Retry-After header. |