This endpoint sends WhatsApp messages through Meta’s WhatsApp Business API.
The organization must have Meta WhatsApp configured and the contact must
already exist.
Overview
Send various types of WhatsApp messages to existing contacts in your FlowIQ organization. The API supports:
Text messages
Media messages (image, video, audio, document)
Location sharing
Contact cards
Interactive messages (buttons, lists)
Reactions to existing messages
Authentication
All requests require a Bearer token with API key format (fiq_...) in the Authorization header:
Authorization: Bearer fiq_YOUR_API_KEY
Only API keys with the fiq_ prefix are accepted. The API key must belong to
the organization specified in tenantId.
Requirements
Prerequisites
Meta WhatsApp Provider : Organization must have
whatsapp_provider_choice set to meta 2. Configured Credentials :
meta_phone_id and whatsapp_bearer_token must be set 3. Existing
Contact : The recipient must already exist in your contacts database
Basic Usage
Send a Text Message
curl -X POST "https://api.flowiq.live/send-whatsapp?tenantId=YOUR_TENANT_ID" \
-H "Authorization: Bearer fiq_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+27123456789",
"message_type": "text",
"text": "Hello! This is a test message from FlowIQ API."
}'
Send an Image with Caption
curl -X POST "https://api.flowiq.live/send-whatsapp?tenantId=YOUR_TENANT_ID" \
-H "Authorization: Bearer fiq_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+27123456789",
"message_type": "image",
"media_url": "https://example.com/image.jpg",
"caption": "Check out this image!"
}'
Reply to a Message
curl -X POST "https://api.flowiq.live/send-whatsapp?tenantId=YOUR_TENANT_ID" \
-H "Authorization: Bearer fiq_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+27123456789",
"message_type": "text",
"text": "This is a reply to your message!",
"context_message_id": "wamid.HBgLMjc4MTIzNDU2NzgVAgASGBQzRUI..."
}'
Request Parameters
Query Parameters
Parameter Type Required Description tenantIdstring Yes Your organization’s tenant identifier (slug)
Request Body (Common Fields)
Field Type Required Description phone_numberstring Yes Recipient phone number with country code message_typestring Yes Type of message (see Message Types below) context_message_idstring No WhatsApp message ID to reply to
Message Types
Text Message
Field Type Required Description textstring Yes The text content of the message
{
"phone_number" : "+27123456789" ,
"message_type" : "text" ,
"text" : "Hello, World!"
}
Image Message
Field Type Required Description media_urlstring Yes URL to the image file captionstring No Optional caption for the image
{
"phone_number" : "+27123456789" ,
"message_type" : "image" ,
"media_url" : "https://example.com/product.jpg" ,
"caption" : "Our latest product!"
}
Supported image formats: JPEG, PNG. The image will be automatically uploaded
to our storage with a 1-year signed URL.
Video Message
Field Type Required Description media_urlstring Yes URL to the video file captionstring No Optional caption for the video
{
"phone_number" : "+27123456789" ,
"message_type" : "video" ,
"media_url" : "https://example.com/demo.mp4" ,
"caption" : "Watch our demo video"
}
Audio Message
Field Type Required Description media_urlstring Yes URL to the audio file
{
"phone_number" : "+27123456789" ,
"message_type" : "audio" ,
"media_url" : "https://example.com/message.mp3"
}
Audio messages do not support captions.
Document Message
Field Type Required Description media_urlstring Yes URL to the document file filenamestring No Display filename for the document captionstring No Optional caption for the document
{
"phone_number" : "+27123456789" ,
"message_type" : "document" ,
"media_url" : "https://example.com/invoice.pdf" ,
"filename" : "Invoice_2025.pdf" ,
"caption" : "Please find your invoice attached"
}
Location Message
Field Type Required Description location.latitudenumber Yes Latitude coordinate location.longitudenumber Yes Longitude coordinate location.namestring No Location name location.addressstring No Location address
{
"phone_number" : "+27123456789" ,
"message_type" : "location" ,
"location" : {
"latitude" : -33.9249 ,
"longitude" : 18.4241 ,
"name" : "Cape Town Office" ,
"address" : "123 Main Street, Cape Town"
}
}
Share one or more contact cards.
Field Type Required Description contactsarray Yes Array of contact objects
{
"phone_number" : "+27123456789" ,
"message_type" : "contacts" ,
"contacts" : [
{
"name" : {
"formatted_name" : "John Doe" ,
"first_name" : "John" ,
"last_name" : "Doe"
},
"phones" : [
{
"phone" : "+27987654321" ,
"type" : "CELL"
}
]
}
]
}
Send a message with up to 3 quick reply buttons.
Field Type Required Description interactive.typestring Yes Must be "button" interactive.bodystring Yes Main message text (max 1024 chars) interactive.headerstring No Header text (max 60 chars) interactive.footerstring No Footer text (max 60 chars) interactive.buttonsarray Yes Array of button objects (max 3) interactive.header_mediaobject No Media header (image/video/document)
{
"phone_number" : "+27123456789" ,
"message_type" : "interactive" ,
"interactive" : {
"type" : "button" ,
"header" : "Order Confirmation" ,
"body" : "Would you like to confirm your order #12345?" ,
"footer" : "Reply within 24 hours" ,
"buttons" : [
{ "id" : "confirm" , "title" : "Confirm" },
{ "id" : "cancel" , "title" : "Cancel" },
{ "id" : "modify" , "title" : "Modify Order" }
]
}
}
{
"phone_number" : "+27123456789" ,
"message_type" : "interactive" ,
"interactive" : {
"type" : "button" ,
"body" : "Check out our new product!" ,
"header_media" : {
"type" : "image" ,
"url" : "https://example.com/product.jpg"
},
"buttons" : [
{ "id" : "buy" , "title" : "Buy Now" },
{ "id" : "info" , "title" : "More Info" }
]
}
}
Button titles are limited to 20 characters. You can have a maximum of 3
buttons.
Interactive List Message
Send a message with a list menu containing multiple sections and rows.
Field Type Required Description interactive.typestring Yes Must be "list" interactive.bodystring Yes Main message text (max 1024 chars) interactive.buttonstring Yes Menu button text (max 20 chars) interactive.headerstring No Header text (max 60 chars) interactive.footerstring No Footer text (max 60 chars) interactive.sectionsarray Yes Array of section objects (max 10)
{
"phone_number" : "+27123456789" ,
"message_type" : "interactive" ,
"interactive" : {
"type" : "list" ,
"header" : "Our Menu" ,
"body" : "Please select from our available options:" ,
"footer" : "Tap the button below to view options" ,
"button" : "View Menu" ,
"sections" : [
{
"title" : "Main Dishes" ,
"rows" : [
{
"id" : "burger" ,
"title" : "Burger" ,
"description" : "Beef patty with cheese"
},
{
"id" : "pizza" ,
"title" : "Pizza" ,
"description" : "Margherita or Pepperoni"
}
]
},
{
"title" : "Drinks" ,
"rows" : [
{ "id" : "cola" , "title" : "Cola" , "description" : "500ml bottle" },
{
"id" : "water" ,
"title" : "Water" ,
"description" : "Still or sparkling"
}
]
}
]
}
}
List messages support up to 10 sections with up to 10 rows each. Row titles
are limited to 24 characters and descriptions to 72 characters.
Reaction Message
React to an existing message with an emoji.
Field Type Required Description reaction.message_idstring Yes WhatsApp message ID to react to reaction.emojistring No Emoji to react with (default: 👍)
{
"phone_number" : "+27123456789" ,
"message_type" : "reaction" ,
"reaction" : {
"message_id" : "wamid.HBgLMjc4MTIzNDU2NzgVAgASGBQzRUI..." ,
"emoji" : "❤️"
}
}
Response Examples
Success Response (200)
{
"success" : true ,
"message" : "Message sent successfully" ,
"data" : {
"message_id" : "wamid.HBgLMjc4MTIzNDU2NzgVAgASGBQzRUI..." ,
"recipient" : "27123456789" ,
"message_type" : "text" ,
"organization" : "Your Organization Name" ,
"meta_response" : {
"messaging_product" : "whatsapp" ,
"contacts" : [{ "input" : "27123456789" , "wa_id" : "27123456789" }],
"messages" : [{ "id" : "wamid.HBgLMjc4MTIzNDU2NzgVAgASGBQzRUI..." }]
}
}
}
{
"error" : "Contact not found" ,
"message" : "No contact exists with WhatsApp number 27123456789. Please create the contact first using the /api/contact endpoint." ,
"whatsapp_id" : "27123456789"
}
Error: Invalid Provider (400)
{
"error" : "Invalid provider" ,
"message" : "Organization must use Meta WhatsApp provider. Current: wati"
}
Error: Missing Required Field (400)
{
"error" : "Missing required field" ,
"message" : "text is required for text messages"
}
Error: Invalid API Key (401)
{
"error" : "Invalid API key" ,
"message" : "API key has been revoked"
}
{
"error" : "Meta upload failed" ,
"message" : "Failed to upload media to Meta"
}
Media Upload Flow When you send media messages, the API automatically: 1. Downloads the media
from your provided URL 2. Uploads it to FlowIQ’s storage bucket 3. Generates a
1-year signed URL 4. Uploads to Meta’s servers for delivery 5. Stores the
signed URL in the message database
This ensures:
Media is permanently stored for future reference
URLs won’t expire or break
Messages can be viewed in the FlowIQ inbox
Supported media types: - Images : JPEG, PNG - Videos : MP4 - Audio :
MP3, AAC, OGG - Documents : PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX
Error Codes
Status Code Error Description 200 Success Message sent successfully 400 Bad Request Missing required fields, invalid message type, or invalid provider 401 Unauthorized Invalid or expired API key, or tenant mismatch 404 Not Found Organization or contact not found 500 Internal Server Error Meta upload failed or server error
Best Practices
Contact Requirement Always ensure the contact exists before sending messages. Use the /contact
endpoint to create contacts first.
Phone Number Format Include the country code in phone numbers (e.g., +27 for South Africa). The
API removes special characters automatically.
Media URLs Ensure media URLs are publicly accessible. The API needs to download the file
before uploading to Meta.
Interactive Messages Use interactive buttons and lists for better engagement. They provide a better
user experience than plain text.
Message Context Use context_message_id when replying to specific messages. This creates a
visual thread in the WhatsApp conversation.
Integration Example
async function sendWhatsAppMessage ( tenantId , apiKey , messageData ) {
try {
const response = await fetch (
`https://api.flowiq.live/send-whatsapp?tenantId= ${ tenantId } ` ,
{
method: "POST" ,
headers: {
Authorization: `Bearer ${ apiKey } ` ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ( messageData ),
}
);
const data = await response . json ();
if ( ! response . ok ) {
if ( response . status === 404 ) {
console . error ( "Contact not found:" , data . message );
// Handle contact creation first
} else if ( response . status === 400 ) {
console . error ( "Invalid request:" , data . message );
}
throw new Error ( data . message );
}
return data ;
} catch ( error ) {
console . error ( "Failed to send message:" , error );
throw error ;
}
}
// Send a text message
const textResult = await sendWhatsAppMessage (
"your-tenant-id" ,
"fiq_your_api_key" ,
{
phone_number: "+27123456789" ,
message_type: "text" ,
text: "Hello from the FlowIQ API!" ,
}
);
// Send an interactive button message
const buttonResult = await sendWhatsAppMessage (
"your-tenant-id" ,
"fiq_your_api_key" ,
{
phone_number: "+27123456789" ,
message_type: "interactive" ,
interactive: {
type: "button" ,
body: "How would you like to proceed?" ,
buttons: [
{ id: "yes" , title: "Yes, continue" },
{ id: "no" , title: "No, cancel" },
],
},
}
);
// Send a document with caption
const docResult = await sendWhatsAppMessage (
"your-tenant-id" ,
"fiq_your_api_key" ,
{
phone_number: "+27123456789" ,
message_type: "document" ,
media_url: "https://example.com/report.pdf" ,
filename: "Monthly_Report.pdf" ,
caption: "Please review the attached report" ,
}
);
Rate Limiting
The WhatsApp Business API has rate limits imposed by Meta. If you exceed these
limits, messages may fail to send. Implement exponential backoff and respect
429 responses.
Message Storage
All sent messages are automatically stored in:
helpdesk_messages : Full message details including media URLs
customer_sessions : Message history for the conversation thread
This enables message history viewing in the FlowIQ inbox and conversation tracking. Bearer token for authentication. Format: Bearer YOUR_BEARER_TOKEN
Organization tenant identifier (slug)
Recipient phone number with country code
Available options:
text,
image,
video,
audio,
document,
location,
contacts,
interactive,
reaction
Text content (required for text messages)
URL to media file (required for image/video/audio/document)
Example: "https://example.com/image.jpg"
Caption for media messages
Filename for document messages
Example: "123 Main Street, Cape Town"
Array of contact cards to share
Interactive message configuration
Type of interactive message
Available options:
button,
list
Main message body text (max 1024 chars)
Header text (max 60 chars)
Footer text (max 60 chars)
Array of buttons (max 3, for button type)
interactive.buttons. title
Button text (max 20 chars)
Menu button text for list type (max 20 chars)
Array of sections (max 10, for list type)
interactive.sections. title
Section title (max 24 chars)
interactive.sections. rows
interactive.sections.rows. id
interactive.sections.rows. title
interactive.sections.rows. description
Row description (max 72 chars)
Media header for button messages
interactive.header_media. type
Available options:
image,
video,
document
interactive.header_media. url
interactive.header_media. filename
WhatsApp message ID to react to
WhatsApp message ID to reply to
Example: "wamid.HBgLMjc4MTIzNDU2NzgVAgASGBQzRUI..."
Message sent successfully
Whether the message was sent successfully
Example: "Message sent successfully"
Example: "wamid.HBgLMjc4MTIzNDU2NzgVAgASGBQzRUI..."
Raw response from Meta API