Outbound Messaging API
The Outbound Messaging API lets an authorized business system send a WhatsApp message through a connected Nviti assistant. Typical uses include transaction receipts, account alerts, order updates, booking reminders, support updates and other event-driven notifications.
Endpoint
POST https://api.nviti.ng/api/v1/messages
Authentication and sender scope
Use the bearer token issued for the integration:
Authorization: Bearer YOUR_OUTBOUND_MESSAGING_TOKEN
Accept: application/json
Content-Type: application/json
Each credential is stored as a hash and bound to one Nviti company and
assistant. It must have the messages:send ability. Credentials can be rate
limited, expired or revoked, and Nviti records when each credential was last
used. The request cannot select or override its configured sender.
Request
Session message
Use text, media, or both while the recipient has an open WhatsApp customer
service window:
{
"recipient_phone_number": "+2348188000005",
"recipient_name": "Wale",
"idempotency_key": "transfer-receipt:TRX-20260826-001",
"text": "Your transfer was completed. Your receipt is attached.",
"media": {
"type": "image",
"url": "https://example.com/receipts/TRX-20260826-001.png",
"caption": "Transfer receipt",
"filename": "transfer-receipt.png"
}
}
| Field | Required | Description |
|---|---|---|
recipient_phone_number |
Yes | International phone number. Formatting spaces and a leading + are accepted. |
recipient_name |
No | Customer name used when Nviti creates a new WhatsApp visitor. |
idempotency_key |
Yes | Unique business-event key, up to 120 characters. Reusing it returns the original queued message. |
text |
Conditional | Message body, up to 4,096 characters. Required when media is absent. |
media |
Conditional | One image, document, audio or video. Required when text is absent. |
media.url |
With media | Public HTTPS URL. Local, private and credential-bearing URLs are rejected. |
media.caption |
No | Caption up to 1,024 characters. |
media.filename |
No | Safe display filename up to 128 characters. |
Approved template message
For business-initiated alerts outside the customer service window, use an approved WhatsApp template already connected to the credential's sender. The API resolves the template inside the credential's company and WhatsApp account; the caller cannot select another sender.
{
"recipient_phone_number": "+2348188000005",
"idempotency_key": "credit-alert:TRX-20260826-001",
"template": {
"name": "transaction_receipt",
"language": "en_US",
"variables": ["Wale", "TRX-20260826-001"]
},
"media": {
"type": "image",
"url": "https://example.com/receipts/TRX-20260826-001.png"
}
}
| Field | Required | Description |
|---|---|---|
template.name |
Yes | Name of an approved template for the credential's WhatsApp sender. |
template.language |
No | Approved template language, such as en_US. |
template.variables |
Conditional | One non-empty string per template variable, in template order. |
media |
Conditional | Required only when the approved template has an image, video or document header; its type must match. |
text and template cannot be used together. Template mode sends the media as
the approved template header, rather than as a second message.
Accepted response
Nviti returns HTTP 202 after persisting the message and placing its delivery
job on the messaging queue:
{
"success": true,
"data": {
"message_id": 12345,
"status": "queued",
"channel": "whatsapp",
"recipient_phone_masked": "*********0005",
"has_text": true,
"has_media": true,
"delivery_mode": "session"
}
}
A repeated idempotency key returns already_queued with the original message
ID and does not create another delivery job.
Errors
| HTTP status | Code | Meaning |
|---|---|---|
401 |
UNAUTHENTICATED |
Token is missing, invalid, expired or revoked. |
403 |
FORBIDDEN |
The credential lacks messages:send. |
409 |
MESSAGE_QUEUE_BUSY |
The same request is currently being queued; retry with the same key. |
422 |
VALIDATION_ERROR |
The request shape is invalid. |
422 |
INVALID_PHONE_NUMBER |
The recipient number is invalid. |
422 |
INVALID_MEDIA |
The media type or URL is unsafe or unsupported. |
422 |
TEMPLATE_NOT_AVAILABLE |
The named template is not approved for the configured sender and language. |
422 |
INVALID_TEMPLATE_VARIABLES |
Template variables are missing, blank or do not match the approved template. |
422 |
TEMPLATE_MEDIA_REQUIRED |
The approved template requires header media. |
422 |
TEMPLATE_MEDIA_NOT_SUPPORTED |
Media was supplied for a template without a media header. |
422 |
TEMPLATE_MEDIA_TYPE_MISMATCH |
The supplied media type does not match the approved header type. |
429 |
RATE_LIMITED |
The credential's per-minute limit was exceeded. |
503 |
MESSAGING_UNAVAILABLE |
The configured assistant or WhatsApp connection is unavailable. |
Operational guidance
- Generate a different credential for every external system.
- Store tokens in a secret manager and rotate them if exposed.
- Use a stable event or transaction identifier as the idempotency key.
- Use approved template mode for business-initiated notifications outside the WhatsApp customer service window. Session text/media may be rejected by Meta when that window is closed.
- Never use the response alone as proof that Meta delivered the message; use Nviti's message status and delivery records for final delivery state.
- Only send messages permitted by WhatsApp policy and the recipient's consent.