WhatsApp Template Messages - Frontend Developer Guide
Overview
The WhatsApp notification API allows you to send WhatsApp messages using Meta-approved message templates. The API supports sending to any phone number (provided in the request) or uses a default recipient if not specified.
API Endpoint
POST /v1/whatsapp/notify
Content-Type: application/json
Authorization: Bearer <firebaseIdToken>
Base URL: https://api.maintor.systems (production)
Authentication: Required - Firebase ID token in Authorization header
Request Format
Required Fields
templateName(string): Name of the approved WhatsApp templatelanguageCode(string): Language code (e.g., "en_US", "es_ES")
Optional Fields
phoneNumber(string): Recipient phone number in E.164 format (e.g., "+972546800360")- If not provided, uses server default
- Can include spaces, dashes, parentheses (will be cleaned automatically)
- Should be 10-15 digits (with or without country code prefix)
headerParameters(object): For templates with header components (image/text)templateParameters(array): For templates with body variable placeholders
Request Examples
Example 1: Basic Template with Image Header (No Phone Number)
{
"templateName": "jaspers_market_image_cta_v1",
"languageCode": "en_US",
"headerParameters": {
"type": "image",
"image": {
"link": "https://example.com/your-image.jpg"
}
}
}
Note: If phoneNumber is not provided, the message will be sent to the server's default recipient.
Example 2: Template with Custom Phone Number
{
"phoneNumber": "+972546800360",
"templateName": "jaspers_market_image_cta_v1",
"languageCode": "en_US",
"headerParameters": {
"type": "image",
"image": {
"link": "https://example.com/your-image.jpg"
}
}
}
Example 3: Template with Body Parameters
{
"phoneNumber": "+972546800360",
"templateName": "ticket_notification",
"languageCode": "en_US",
"templateParameters": [
{
"type": "text",
"text": "John Doe"
},
{
"type": "text",
"text": "#12345"
}
]
}
Example 4: Template with Both Header and Body
{
"phoneNumber": "+972546800360",
"templateName": "full_notification_template",
"languageCode": "en_US",
"headerParameters": {
"type": "image",
"image": {
"link": "https://example.com/image.jpg"
}
},
"templateParameters": [
{
"type": "text",
"text": "John Doe"
},
{
"type": "text",
"text": "Ticket #12345"
}
]
}
Phone Number Format
The phoneNumber field accepts various formats:
- ✅
+972546800360(E.164 format - recommended) - ✅
972546800360(without +, will be added automatically) - ✅
+972-54-6800360(with dashes, will be cleaned) - ✅
+972 (54) 6800360(with spaces and parentheses, will be cleaned) - ❌ Must be 10-15 digits (excluding country code prefix)
Important: The phone number must be valid and the recipient must be in the allowed list (for development mode) or have opted in (for production).
Response Format
Success Response (200 OK)
{
"success": true,
"message": "WhatsApp template message sent successfully",
"messageId": "wamid.HBgMOTcyNTQ2ODAwMzYwFQIAERgSOTQzNzU1NzRFRDE3MUQ5QzU4AA==",
"recipient": "+972546800360",
"templateName": "jaspers_market_image_cta_v1",
"languageCode": "en_US"
}
Error Responses
400 Bad Request - Validation Error:
{
"error": "Validation error",
"message": "phoneNumber must be a valid phone number (10-15 digits, E.164 format preferred, e.g., +972546800360)"
}
400 Bad Request - Missing Required Field:
{
"error": "Validation error",
"message": "templateName is required and must be a non-empty string"
}
401 Unauthorized - Authentication Required:
- Missing or invalid Firebase ID token
500 Internal Server Error - API Error:
{
"error": "WhatsApp API error",
"message": "WhatsApp API error: 400 Bad Request - Template requires an image header but none was provided..."
}
Implementation Examples
JavaScript/Vue.js Example
import { getAuth } from 'firebase/auth';
async function sendWhatsAppNotification(options) {
try {
// Get Firebase ID token
const auth = getAuth();
const user = auth.currentUser;
if (!user) {
throw new Error('User must be authenticated');
}
const idToken = await user.getIdToken();
// Build request body
const body = {
templateName: options.templateName,
languageCode: options.languageCode || 'en_US'
};
// Add phone number if provided
if (options.phoneNumber) {
body.phoneNumber = options.phoneNumber;
}
// Add header parameters if provided
if (options.headerImageUrl) {
body.headerParameters = {
type: 'image',
image: {
link: options.headerImageUrl
}
};
}
// Add body parameters if provided
if (options.bodyParameters && options.bodyParameters.length > 0) {
body.templateParameters = options.bodyParameters.map(text => ({
type: 'text',
text
}));
}
// Send request
const response = await fetch('https://api.maintor.systems/v1/whatsapp/notify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${idToken}`
},
body: JSON.stringify(body)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to send WhatsApp message');
}
const result = await response.json();
return result;
} catch (error) {
console.error('Error sending WhatsApp notification:', error);
throw error;
}
}
// Usage examples:
// Send to specific phone number
await sendWhatsAppNotification({
phoneNumber: '+972546800360',
templateName: 'jaspers_market_image_cta_v1',
languageCode: 'en_US',
headerImageUrl: 'https://example.com/image.jpg'
});
// Send to default recipient (no phoneNumber)
await sendWhatsAppNotification({
templateName: 'jaspers_market_image_cta_v1',
languageCode: 'en_US',
headerImageUrl: 'https://example.com/image.jpg'
});
// Send with body parameters
await sendWhatsAppNotification({
phoneNumber: '+972546800360',
templateName: 'ticket_notification',
languageCode: 'en_US',
bodyParameters: ['John Doe', '#12345']
});
React Hook Example
import { useState } from 'react';
import { getAuth } from 'firebase/auth';
export function useWhatsAppNotification() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [result, setResult] = useState(null);
const sendNotification = async (templateName, languageCode, options = {}) => {
setLoading(true);
setError(null);
setResult(null);
try {
const auth = getAuth();
const user = auth.currentUser;
if (!user) {
throw new Error('User must be authenticated');
}
const idToken = await user.getIdToken();
const body = {
templateName,
languageCode
};
// Add phone number if provided
if (options.phoneNumber) {
body.phoneNumber = options.phoneNumber;
}
if (options.headerImageUrl) {
body.headerParameters = {
type: 'image',
image: {
link: options.headerImageUrl
}
};
}
if (options.bodyParameters) {
body.templateParameters = options.bodyParameters.map(text => ({
type: 'text',
text
}));
}
const response = await fetch('https://api.maintor.systems/v1/whatsapp/notify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${idToken}`
},
body: JSON.stringify(body)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Failed to send message');
}
const data = await response.json();
setResult(data);
return data;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
};
return { sendNotification, loading, error, result };
}
// Usage in component:
function NotificationButton({ phoneNumber, templateName }) {
const { sendNotification, loading, error } = useWhatsAppNotification();
const handleSend = async () => {
try {
await sendNotification(
templateName || 'jaspers_market_image_cta_v1',
'en_US',
{
phoneNumber: phoneNumber, // Optional - omit to use default
headerImageUrl: 'https://example.com/image.jpg'
}
);
alert('Message sent successfully!');
} catch (err) {
alert(`Failed to send: ${err.message}`);
}
};
return (
<button onClick={handleSend} disabled={loading}>
{loading ? 'Sending...' : 'Send WhatsApp Notification'}
</button>
);
}
Common Templates
jaspers_market_image_cta_v1
Required: Image header
Body Parameters: None
Phone Number: Optional
{
"phoneNumber": "+972546800360",
"templateName": "jaspers_market_image_cta_v1",
"languageCode": "en_US",
"headerParameters": {
"type": "image",
"image": {
"link": "https://your-domain.com/image.jpg"
}
}
}
Phone Number Handling
When to Include phoneNumber
- ✅ Include when sending to a specific user (e.g., from user profile, ticket assignment)
- ✅ Include when sending notifications to different recipients
- ✅ Omit when testing or when using a default recipient
Phone Number Priority
- Request body (
phoneNumberfield) - highest priority - Server environment variable (
WHATSAPP_DEFAULT_RECIPIENT) - if set - Hardcoded default - fallback for testing
Best Practices
- Always validate phone numbers on the frontend before sending
- Store phone numbers in E.164 format in your database
- Handle cases where phone number might be missing (use default)
- Show the recipient in the UI when sending (from response.recipient)
Error Handling
Common Errors
-
Invalid Phone Number
phoneNumber must be a valid phone number (10-15 digits, E.164 format preferred)→ Check phone number format and length
-
Missing Image Header
Template requires an image header but none was provided→ Add
headerParameterswith image -
Authentication Error
401 Unauthorized→ Check Firebase ID token is valid
-
Recipient Not Allowed (Development Mode)
Recipient phone number not in allowed list→ Add recipient to Meta Business Manager allowed list
Testing
Testing with Default Recipient
Omit the phoneNumber field to use the server's default:
await sendWhatsAppNotification({
templateName: 'jaspers_market_image_cta_v1',
languageCode: 'en_US',
headerImageUrl: 'https://example.com/image.jpg'
// No phoneNumber - uses default
});
Testing with Specific Recipient
Include phoneNumber to test with a specific number:
await sendWhatsAppNotification({
phoneNumber: '+972546800360',
templateName: 'jaspers_market_image_cta_v1',
languageCode: 'en_US',
headerImageUrl: 'https://example.com/image.jpg'
});
Important Notes
- ✅ Phone number is optional - if omitted, uses server default
- ✅ Phone number format is flexible - accepts various formats (spaces, dashes, etc.)
- ✅ Authentication required - Firebase ID token must be valid
- ✅ Image URLs must be publicly accessible - HTTPS required
- ✅ Templates must be pre-approved - only approved templates can be sent
- ⚠️ Development mode restrictions - recipients must be in allowed list
API Reference
For complete API documentation, see: openapi.json (search for /v1/whatsapp/notify)
Support
If you encounter issues:
- Check the error message in the response
- Verify phone number format (10-15 digits)
- Ensure image URLs are publicly accessible
- Check that authentication token is valid
- Verify template name and structure match Meta's approved template