Messaging
Send and receive WhatsApp messages with Sendable.
Message Types
Sendable supports various message types for different use cases.
Text Messages
Simple text messages for notifications and conversations:
{
"to": "6281234567890",
"text": "Hello! Your order #12345 has been shipped."
}Group Mentions
To send a real WhatsApp mention in a group, include the visible @number in
text.content and the full WhatsApp JID in mentions:
{
"chatId": "[email protected]",
"text": {
"content": "asd @6285176702468"
},
"mentions": ["[email protected]"]
}Media Messages
Send images, videos, documents:
{
"to": "6281234567890",
"mediaUrl": "https://example.com/invoice.pdf",
"mediaType": "document",
"caption": "Your invoice for order #12345"
}Supported media types:
image- JPG, PNGvideo- MP4audio- MP3, OGGdocument- PDF, DOC, etc.
Sending Messages
Dashboard
Send quick messages directly from the dashboard:
- Go to your session
- Click "Send Message"
- Enter phone number
- Type message or attach media
- Send
API
Send programmatically via API:
curl -X POST "https://api.sendable.dev/messages/send" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "6281234567890",
"text": "Hello from API!"
}'Message Status
Track message delivery status:
| Status | Meaning |
|---|---|
pending | Queued for sending |
sent | Sent to WhatsApp servers |
delivered | Delivered to recipient's phone |
read | Recipient opened the message |
failed | Could not be delivered |
Check Status via API
curl "https://api.sendable.dev/messages/{messageId}/status" \
-H "x-api-key: YOUR_API_KEY"Real-time Updates
Use webhooks to get instant status updates:
message.delivered- Message arrivedmessage.read- Message seenmessage.failed- Delivery failed
Receiving Messages
Webhook Setup
Configure webhook to receive incoming messages:
- Go to session → Webhooks
- Subscribe to
message.receivedevent - Your endpoint receives:
{
"event": "message.received",
"data": {
"messageId": "msg_incoming_456",
"from": "6281234567890",
"type": "text",
"text": "Hi, I have a question about my order",
"timestamp": "2026-03-02T10:30:00Z"
}
}Auto-Reply
Example: Automatic response to incoming messages:
app.post('/webhook', (req, res) => {
const { event, data } = req.body
if (event === 'message.received') {
// Send auto-reply
sendMessage(data.from,
"Thanks for your message! We'll respond shortly.")
}
res.sendStatus(200)
})Use Cases
Customer Support
Two-way conversation handling:
// Store incoming messages
if (event === 'message.received') {
await createTicket({
customer: data.from,
message: data.text,
timestamp: data.timestamp
})
}
// Notify agents
await notifySupportTeam(newTicket)Order Notifications
Automated order updates:
// Order confirmation
await sendMessage(customerPhone,
`Order #${orderId} confirmed! Total: $${amount}`)
// Shipping notification
await sendMessage(customerPhone,
`Order #${orderId} shipped! Track: ${trackingUrl}`)
// Delivery confirmation
await sendMessage(customerPhone,
`Order #${orderId} delivered! Enjoy your purchase.`)Appointment Reminders
Reduce no-shows with reminders:
// 24 hours before
await sendMessage(patientPhone,
`Reminder: Appointment with Dr. Smith tomorrow at ${time}`)
// 1 hour before
await sendMessage(patientPhone,
`Your appointment starts in 1 hour. See you soon!`)OTP Verification
Secure authentication codes:
// Generate and send OTP
const otp = generateOTP()
await sendMessage(userPhone,
`Your verification code is: ${otp}. Valid for 5 minutes.`)Message Templates
Create reusable message formats:
const templates = {
welcome: (name) => `Hi ${name}! Welcome to our service.`,
orderShipped: (orderId, tracking) =>
`Order #${orderId} shipped! Track: ${tracking}`,
appointmentReminder: (doctor, time) =>
`Reminder: Appointment with ${doctor} at ${time}`
}
// Usage
await sendMessage(phone, templates.welcome('John'))Best Practices
Phone Number Format
Always use international format:
- ✅
6281234567890(Indonesia) - ❌
081234567890(missing country code) - ❌
+6281234567890(remove the +)
Message Length
- Keep messages concise
- WhatsApp has no strict limit, but split long messages
- Use formatting (bold, italic) for emphasis
Timing
- Business hours for promotional messages
- Immediate for OTPs and alerts
- Consider timezone of recipient
Personalization
Include customer details:
Hi {name}, your order #{orderId} is ready!Error Handling
Always handle delivery failures:
try {
const result = await sendMessage(phone, text)
if (!result.success) {
// Log failure
await logFailedMessage(phone, text, result.error)
// Retry or notify
if (isRetryable(result.error)) {
await retryLater(phone, text)
}
}
} catch (error) {
await notifyAdmin(error)
}Rate Limits
Be aware of sending limits:
| Plan | Messages/Hour | Notes |
|---|---|---|
| Free | 100 | Best for testing |
| Starter | 1,000 | Small businesses |
| Pro | 10,000 | High volume |
| Enterprise | Custom | Unlimited |
Monitor your usage in the dashboard.