Integrate your Service with SMS API
Overview
The SMS API Integration enables third-party SMS aggregators to connect natively with Optimove’s SMS module. This integration flips the traditional model—instead of Optimove building dedicated connectors for every provider, your service can now integrate directly using our standardized API.
This approach is particularly valuable for connecting with local operators or niche providers without requiring specific R&D development cycles. By integrating your service with the SMS API, you act as the execution channel for SMS campaigns orchestrated by Optimove, utilizing a bi-directional flow to handle campaign transmission, delivery reporting, and incoming customer messages.
This document details the four critical flows required for integration:
- Configuration: Setting up credentials in the Optimove UI.
- Handshake: Establishing the authenticated connection (replaces traditional webhook registration).
- Campaign Transmission: Receiving campaign batches from Optimove.
- Delivery & Incoming Reporting: Sending status updates and replies back to Optimove.
Integration Architecture

High-level sequence diagram of the SMS API integration flows.
Authentication and Security
All endpoints in this integration require strict authentication to ensure data integrity.
Required Headers
Every request (both inbound to Optimove and outbound to the Aggregator) must include the following headers. Note the difference in the API Key header name depending on the direction.
| Flow | Direction | API Key Header | Signature Header |
|---|---|---|---|
| Handshake | To Optimove | app-api-key | x-hub-signature |
| Delivery Report | To Optimove | app-api-key | x-hub-signature |
| Incoming Message | To Optimove | app-api-key | x-hub-signature |
| Campaign Transmission | To Aggregator | X-API-Key | x-hub-signature |
HMAC Signature Generation
The x-hub-signature header contains an HMAC-SHA256 signature of the request body using the shared Secret Key provided during configuration. The signature format follows the GitHub webhook signature format: sha256={signature}.
Example (Node.js):
const crypto = require("crypto");
const payload = JSON.stringify(requestBody);
const secret = "your-shared-secret";
const signature = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
const hubSignature = `sha256=${signature}`;Example (Python):
import hashlib
import hmac
import json
payload = json.dumps(request_body, separators=(',', ':'))
secret = b'your-shared-secret'
signature = hmac.new(secret, payload.encode(), hashlib.sha256).hexdigest()
hub_signature = f'sha256={signature}'Obtaining Credentials
Before initiating the API flows, you must obtain the credentials from the Optimove tenant.
- In the Optimove interface, navigate to Settings > SMS Configuration.
- Select the API Vendor option (currently labeled OptiText API Vendor in the UI).
- Once the feature is enabled, you will see the following read-only credentials:
- Base URL: The endpoint URL for SMS API calls.
- API Token: The unique token identifying the tenant.
- Secret Key: Used for HMAC signature generation.
Important: The Secret Key is only visible in this screen before the Handshake is completed. Once you successfully perform the Handshake (Flow 1), the Secret Key will be hidden for security.
Flow 1: Handshake Endpoint
Direction: Aggregator -> Optimove
The handshake is a one-time setup call that connects your aggregator service to the tenant's SMS instance. It registers your callback URL for receiving campaigns and sets the default Sender ID.
- URL:
{baseurl}/api/v1/aggregator/handshake - Method:
POST
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
aggregatorApiKey | String | Yes | Your API key that Optimove will use to authenticate when sending campaigns. |
campaignSendUrl | String | Yes | The webhook URL on your system where Optimove will POST campaign requests. |
senderId | String | Yes | Default sender identifier used for campaigns. |
Example Request:
curl -X POST "{baseurl}/api/v1/aggregator/handshake" -H "Content-Type: application/json" -H "app-api-key: {your-app-api-key}" -H "x-hub-signature: sha256={signature}" -d '{
"aggregatorApiKey": "your-aggregator-api-key",
"campaignSendUrl": "https://your-aggregator.com/api/v1/campaigns/send",
"senderId": "YourCompany"
}'Responses
- 200 OK: Handshake completed successfully.
- 409 Conflict: Handshake data unchanged (duplicate request).
- 500 Internal Server Error: Handshake failed.
Flow 2: Campaign Transmission Webhook
Direction: Optimove -> Aggregator
Once the handshake is complete, Optimove will use the campaignSendUrl provided in Flow 1 to transmit SMS campaign batches to your service.
- URL: Defined by you in Flow 1.
- Method:
POST - Headers: Includes
X-API-Key(your key) andx-hub-signature.
Request Body Structure
| Field | Type | Description |
|---|---|---|
batchId | String | Unique identifier for the message batch. |
recipients | Array | Array of recipient objects containing message data. |
metadata | Object | Campaign context (Required for Flow 3). |
Recipient Object:
| Field | Type | Description |
|---|---|---|
message | String | SMS text to send. |
mobileNumber | String | Recipient’s mobile number (E.164). |
customerId | String | Unique customer identifier. |
Metadata Object Details:
| Field | Type | Description |
|---|---|---|
appId | Integer | Application identifier. |
campaignId | String | Campaign identifier. |
campaignType | Integer | 1 (Scheduled) or 2 (Triggered). |
channelId | Integer | Communication channel identifier. |
scheduledTime | Long | Unix timestamp in milliseconds. |
tenantId | Integer | Tenant identifier. |
Example Request:
{
"batchId": "batch-123",
"metadata": {
"appId": 123,
"campaignId": "232522",
"campaignType": 1,
"channelId": 493,
"scheduledTime": 1704106200000,
"tenantId": 1
},
"recipients": [
{
"message": "Hello! Your order is ready.",
"mobileNumber": "+1234567890",
"customerId": "customer-001"
}
]
}Response & Retry Logic
| Status Code | Optimove Behavior |
|---|---|
| 2xx | Success — no retry. |
| 429 | Will retry with exponential backoff. |
| 500/503 | Will retry with exponential backoff. |
| 400-422 | No retry — campaign aborted for that request. |
Flow 3: Delivery Report Endpoint
Direction: Aggregator -> Optimove
URL: {baseurl}/api/v1/aggregator/delivery-report
Method: POST
Request Body
| Section | Field | Required | Description |
|---|---|---|---|
type | status | Yes | Delivered, Failed, or Unknown. |
subStatus | Yes | See mapping table. | |
recipient | mobileNumber | Yes | Recipient's number. |
customerId | Yes | Unique identifier. | |
metadata | all fields | Yes | Must match Flow 2 metadata exactly. |
Status Mapping
| Result | Status | SubStatus |
|---|---|---|
| Success | Delivered | DeliveredToHandset |
| Invalid Number | Failed | InvalidNumber |
| General Failure | Failed | Failed |
| Unknown | Unknown | Unknown |
Example Request:
{
"type": {
"status": "Delivered",
"subStatus": "DeliveredToHandset"
},
"recipient": {
"mobileNumber": "+1234567890",
"customerId": "customer-123"
},
"metadata": {
"appId": 123,
"campaignId": "campaign-789",
"tenantId": 456,
"channelId": 493,
"campaignType": 1,
"scheduledTime": 1735737600000
}
}Flow 4: Incoming Messages Webhook
Direction: Aggregator -> Optimove
URL: {baseurl}/api/v1/aggregator/incoming-message
Method: POST
Request Body
| Field | Type | Description |
|---|---|---|
to | String | Brand or sender ID. |
from | String | Customer’s phone number. |
message | String | Inbound message text. |
sentAt | String | ISO 8601 timestamp. |
Example Request:
{
"messages": [
{
"to": "YourBrand",
"from": "1234567891",
"message": "stop",
"sentAt": "2025-10-01T12:34:56Z"
}
]
}Best Practices
Security & Authentication
- Validate Signatures: Always verify the
x-hub-signatureon every incoming request (Handshake, Transmission) using your shared Secret Key before processing the payload. - Constant-Time Comparison: When verifying HMAC signatures, use a constant-time comparison function (e.g.,
hmac.compare_digestin Python) to prevent timing attacks. - HTTPS Only: Ensure all endpoints (both yours and Optimove's) are accessed over HTTPS to protect sensitive customer data and credentials in transit.
Timing & Retries
- Real-Time Reporting: Send delivery reports immediately as messages are processed. Do not batch them for long periods or delay reports while waiting for a "final" status if an intermediate one is available.
- Exponential Backoff: Implement exponential backoff for retrying failed requests (e.g., network timeouts, 500-level errors) to avoid overwhelming the API.
- Do Not Retry Client Errors: Never retry 400-level errors (e.g., 400 Bad Request, 401 Unauthorized), as these indicate a permanent issue with the request format or credentials.
Data Integrity
- Preserve Metadata: You must return the exact
metadataobject received in the Campaign Transmission payload when sending Delivery Reports. This allows Optimove to map the status back to the correct Tenant, Campaign, and Customer. - Exact Number Formatting: Ensure mobile numbers in reports match the format received in the transmission payload exactly.
Monitoring
- Alert on Failures: Set up internal alerts for high rates of signature verification failures or 401 Unauthorized responses, which could indicate a configuration drift or security issue.
- Track Success Rates: Monitor the success rate of your delivery report submissions to ensure campaign analytics in Optimove remain accurate.
Updated about 2 hours ago
