WhatsApp Messaging API
Send and receive WhatsApp messages programmatically outside the Wallin Inbox.
Base URL: {WALLIN_URL}/api/whatsapp
All endpoints require Sanctum authentication (see Authentication) and a valid tenant context.
POST /send-text
Send a text message to a customer.
Request:
curl -X POST https://wallin.example/api/whatsapp/send-text \
-H "Authorization: Bearer 1|abc123..." \
-H "Content-Type: application/json" \
-d '{
"business_account_id": 1,
"to": "+201001234567",
"message": "Hello! How can I help?",
"conversation_id": 42
}'
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
business_account_id |
integer | yes | ID of the WhatsApp Business Account (ChannelConnection) |
to |
string | yes | Recipient phone in E.164 format (e.g., +201001234567) |
message |
string | yes | Message text (max 4,096 characters) |
conversation_id |
integer | no | Conversation ID to link this message to (creates a record in conversation threads) |
Response (200 OK):
{
"success": true,
"message_id": 123,
"whatsapp_message_id": "wamid_abc123xyz"
}
Errors:
400 Bad Request β Invalid parameters:
{
"message": "The to field is required.",
"errors": {
"to": ["The to field is required."]
}
}
401 Unauthorized β Missing or invalid token (see Authentication)
403 Forbidden β Business account doesn't belong to your organization:
{
"message": "This action is unauthorized."
}
500 Internal Server Error β Send failed (connection error, rate limited by Meta, etc.):
{
"error": "Failed to send message"
}
POST /send-template
Send a pre-approved template message.
Request:
curl -X POST https://wallin.example/api/whatsapp/send-template \
-H "Authorization: Bearer 1|abc123..." \
-H "Content-Type: application/json" \
-d '{
"business_account_id": 1,
"to": "+201001234567",
"template_name": "hello_world",
"language_code": "en",
"parameters": ["Ahmad", "ORD-123"],
"conversation_id": 42
}'
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
business_account_id |
integer | yes | ID of the WhatsApp Business Account |
to |
string | yes | Recipient phone in E.164 format |
template_name |
string | yes | Template name (e.g., hello_world) |
language_code |
string | yes | Template language (e.g., en, ar) |
parameters |
array | no | Ordered list of variable values (replaces {{1}}, {{2}}, etc.) |
conversation_id |
integer | no | Conversation ID for threading |
Response (200 OK):
{
"success": true,
"message_id": 123,
"whatsapp_message_id": "wamid_abc123xyz"
}
Errors:
400 Bad Requestβ Template not found or invalid language401 Unauthorizedβ Invalid token403 Forbiddenβ Business account not yours500 Internal Server Errorβ Send failed
Notes:
- Template must be Approved by Meta to send
- If template is not approved, send fails with a 500 error
- Parameters are optional; include only if the template has variables
POST /mark-read
Mark messages as read.
Request:
curl -X POST https://wallin.example/api/whatsapp/mark-read \
-H "Authorization: Bearer 1|abc123..." \
-H "Content-Type: application/json" \
-d '{
"business_account_id": 1,
"message_id": "wamid_abc123xyz"
}'
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
business_account_id |
integer | yes | WhatsApp Business Account ID |
message_id |
string | yes | The WhatsApp message ID (from received message or sent response) |
Response (200 OK):
{
"success": true
}
GET /media/{mediaId}
Download a media file (image, audio, video, document) from a received message.
Request:
curl -X GET https://wallin.example/api/whatsapp/media/abc123xyz \
-H "Authorization: Bearer 1|abc123..."
Response (200 OK):
Binary file content with appropriate Content-Type header (image/jpeg, application/pdf, etc.)
Errors:
404 Not Foundβ Media ID doesn't exist401 Unauthorizedβ Invalid token403 Forbiddenβ Media doesn't belong to your organization
GET /media/{mediaId}/url
Get the download URL for a media file (instead of downloading directly).
Request:
curl -X GET https://wallin.example/api/whatsapp/media/abc123xyz/url \
-H "Authorization: Bearer 1|abc123..."
Response (200 OK):
{
"url": "https://wallin.example/api/whatsapp/media/abc123xyz",
"expires_at": "2024-07-20T10:00:00Z"
}
This is useful if you want to embed the download URL in a webpage or email rather than serving the file directly.
Business Account Profile
GET /business-account/{businessAccountId}/profile
Retrieve business profile information.
Request:
curl -X GET https://wallin.example/api/whatsapp/business-account/1/profile \
-H "Authorization: Bearer 1|abc123..."
Response (200 OK):
{
"data": {
"name": "Acme Corp Support",
"phone_number": "+201012345678",
"website": "https://example.com",
"description": "We're here to help",
"email": "support@example.com",
"address": "123 Main St, Cairo, Egypt",
"profile_picture_url": "https://..."
}
}
PUT /business-account/{businessAccountId}/profile
Update business profile.
Request:
curl -X PUT https://wallin.example/api/whatsapp/business-account/1/profile \
-H "Authorization: Bearer 1|abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp Support",
"website": "https://example.com",
"email": "support@example.com",
"phone_number": "+201012345678",
"description": "We're here to help",
"address": "123 Main St, Cairo, Egypt"
}'
Response (200 OK):
{
"success": true
}
Templates
GET /business-account/{businessAccountId}/templates
List all templates for a business account.
Request:
curl -X GET https://wallin.example/api/whatsapp/business-account/1/templates \
-H "Authorization: Bearer 1|abc123..."
Response (200 OK):
{
"data": [
{
"id": 1,
"name": "hello_world",
"status": "APPROVED",
"language": "en",
"category": "MARKETING",
"body": "Hello {{1}}, welcome!"
}
]
}
Media Upload
POST /business-account/{businessAccountId}/upload-media
Upload a media file for use in templates or messages.
Request:
curl -X POST https://wallin.example/api/whatsapp/business-account/1/upload-media \
-H "Authorization: Bearer 1|abc123..." \
-F "file=@/path/to/image.jpg" \
-F "type=image"
Form Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
file |
file | yes | Media file (image, document, audio, video) |
type |
string | yes | One of: image, document, audio, video |
Response (200 OK):
{
"success": true,
"media_id": "abc123xyz"
}
Use the media_id in template headers or other template components.
Messaging Window
WhatsApp messaging windows limit when you can send:
- Customer-Service Window β You can send freely within 24 hours of the customer's last message
- Window Closed β After 24 hours of silence, you must wait for the customer to message first
Free-form messages fail if the window is closed. Templates tagged MARKETING or OTP may bypass this restriction (depending on Meta's current rules).
Rate Limiting
WhatsApp API calls are rate-limited by Meta and by your plan:
| Limit | Value |
|---|---|
| Sends per second per account | Determined by Meta WABA quality rating |
| Monthly message limit | Plan-dependent (1Kβunlimited) |
Exceeding rate limits returns 429 Too Many Requests with a Retry-After header. Queue or retry after the specified delay.
Testing
For local testing, set WHATSAPP_SIMULATE_API=true in .env. Requests will be accepted but no actual message is sent to WhatsApp β responses are mocked. Useful for CI/CD and local development.