WhatsApp API Message Templates (HSM)
Panduan lengkap WhatsApp API message templates (HSM). Cara buat, approval process, variables, kategori. Tutorial developer!
Template = Wajib untuk business-initiated!
WhatsApp Business API mengharuskan penggunaan pre-approved templates untuk mengirim pesan pertama ke customer. Ini disebut HSM (Highly Structured Messages).
Kapan Perlu Template?
š ATURAN:
PERLU TEMPLATE (Business-initiated):
- Kamu yang mulai conversation
- Kirim pesan setelah 24 jam
- Broadcast/bulk message
- Notifikasi proaktif
TIDAK PERLU TEMPLATE (User-initiated):
- Customer yang chat duluan
- Reply dalam 24 jam window
- Conversation masih aktifKategori Template
š KATEGORI:
UTILITY (Transactional):
- Order confirmation
- Shipping updates
- Appointment reminders
- Account alerts
š° Biaya: Lebih murah
AUTHENTICATION:
- OTP codes
- Login verification
- Security alerts
š° Biaya: Paling murah
MARKETING:
- Promotions
- Product announcements
- Newsletters
š° Biaya: Lebih mahal
ā ļø Perlu opt-in explicitMembuat Template
Via Meta Business Suite:
š LANGKAH:
1. Buka Meta Business Suite
2. WhatsApp Manager > Templates
3. Create Template
4. Isi:
⢠Name: order_confirmation
⢠Category: Utility
⢠Language: Indonesian
⢠Header (optional): Media/Text
⢠Body: Isi pesan + variables
⢠Footer (optional): Text
⢠Buttons (optional): CTA/Quick Reply
5. Submit for Review
6. Tunggu approval (5 menit - 24 jam)Contoh Template:
š TEMPLATE: order_confirmation
HEADER:
[Image: Order logo]
BODY:
Hai {{1}}! š
Terima kasih sudah order di [Brand]!
š¦ Order: #{{2}}
š° Total: Rp {{3}}
š
Tanggal: {{4}}
Pesanan kamu sedang diproses!
FOOTER:
Balas pesan ini jika ada pertanyaan
BUTTONS:
[Track Order] ā https://brand.com/track/{{2}}
[Hubungi CS] ā Quick ReplyVariables (Parameters):
š ATURAN VARIABLES:
FORMAT:
- {{1}}, {{2}}, {{3}} dst
- Urut dari 1
- Tidak boleh loncat
CONTOH:
"Hai {{1}}, order {{2}} senilai Rp {{3}}"
AKAN JADI:
"Hai Budi, order #ORD-123 senilai Rp 500.000"
BATASAN:
- Max 1024 karakter body
- Max 60 karakter header text
- Max 60 karakter footer
- Max 3 buttonsSubmit via API
Create Template:
javascript
const axios = require('axios');
const WABA_ID = process.env.WHATSAPP_BUSINESS_ACCOUNT_ID;
const ACCESS_TOKEN = process.env.ACCESS_TOKEN;
async function createTemplate(template) {
const url = `https://graph.facebook.com/v17.0/${WABA_ID}/message_templates`;
const payload = {
name: template.name,
category: template.category, // UTILITY, AUTHENTICATION, MARKETING
language: template.language,
components: template.components
};
try {
const response = await axios.post(url, payload, {
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});
return {
success: true,
templateId: response.data.id,
status: response.data.status
};
} catch (error) {
return {
success: false,
error: error.response?.data?.error
};
}
}
// Contoh usage
const template = {
name: 'order_shipped',
category: 'UTILITY',
language: 'id',
components: [
{
type: 'HEADER',
format: 'TEXT',
text: 'š¦ Pesanan Dikirim!'
},
{
type: 'BODY',
text: 'Hai {{1}}!\n\nPesanan {{2}} sudah dikirim via {{3}}.\n\nš Resi: {{4}}\nš
Estimasi: {{5}}\n\nTrack pengiriman kamu!',
example: {
body_text: [
['Budi', 'ORD-123', 'JNE', '1234567890', '2-3 hari']
]
}
},
{
type: 'FOOTER',
text: 'Terima kasih sudah belanja!'
},
{
type: 'BUTTONS',
buttons: [
{
type: 'URL',
text: 'Track Pesanan',
url: 'https://brand.com/track/{{1}}',
example: ['ORD-123']
}
]
}
]
};
createTemplate(template);Kirim Template Message
Basic Send:
javascript
async function sendTemplateMessage(to, templateName, params) {
const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID;
const url = `https://graph.facebook.com/v17.0/${PHONE_NUMBER_ID}/messages`;
const payload = {
messaging_product: 'whatsapp',
to: to,
type: 'template',
template: {
name: templateName,
language: { code: 'id' },
components: params
}
};
const response = await axios.post(url, payload, {
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});
return response.data;
}
// Usage
await sendTemplateMessage('628123456789', 'order_shipped', [
{
type: 'body',
parameters: [
{ type: 'text', text: 'Budi' },
{ type: 'text', text: 'ORD-123' },
{ type: 'text', text: 'JNE REG' },
{ type: 'text', text: '1234567890' },
{ type: 'text', text: '2-3 hari' }
]
},
{
type: 'button',
sub_type: 'url',
index: 0,
parameters: [
{ type: 'text', text: 'ORD-123' }
]
}
]);Dengan Media Header:
javascript
// Template dengan image header
await sendTemplateMessage('628123456789', 'promo_image', [
{
type: 'header',
parameters: [
{
type: 'image',
image: {
link: 'https://brand.com/promo.jpg'
}
}
]
},
{
type: 'body',
parameters: [
{ type: 'text', text: 'Budi' },
{ type: 'text', text: '50%' }
]
}
]);
// Template dengan document header
await sendTemplateMessage('628123456789', 'invoice_pdf', [
{
type: 'header',
parameters: [
{
type: 'document',
document: {
link: 'https://brand.com/invoice.pdf',
filename: 'Invoice-ORD123.pdf'
}
}
]
},
{
type: 'body',
parameters: [
{ type: 'text', text: 'ORD-123' },
{ type: 'text', text: 'Rp 500.000' }
]
}
]);Template Status
š STATUS TEMPLATE:
PENDING:
- Sedang review
- Tunggu 5 menit - 24 jam
APPROVED:
- Siap digunakan
- Bisa kirim ke customers
REJECTED:
- Tidak lolos review
- Lihat alasan rejection
- Buat ulang / appeal
PAUSED:
- Di-pause oleh Meta
- Quality issue
- Banyak block/reportCek Status via API:
javascript
async function getTemplates() {
const url = `https://graph.facebook.com/v17.0/${WABA_ID}/message_templates`;
const response = await axios.get(url, {
headers: { 'Authorization': `Bearer ${ACCESS_TOKEN}` },
params: { limit: 100 }
});
return response.data.data.map(t => ({
name: t.name,
status: t.status,
category: t.category,
language: t.language
}));
}Tips Approval
DO ā
ā
TIPS LOLOS APPROVAL:
- Jelas tujuannya (utility/marketing)
- Tidak ada konten prohibited
- Variables punya example
- Grammar benar
- Tidak misleading
- Sertakan opt-out untuk marketing
- Brand name konsistenContoh Rejected:
ā ALASAN REJECTED:
- "Spam" atau "promosi berlebihan"
- Konten dewasa/ilegal
- Tidak ada example untuk variables
- Typo atau grammar salah
- Menyesatkan/clickbait
- Meminta info sensitif
- URL mencurigakanTemplate Library
Order Confirmation:
Hai {{1}}! š
Terima kasih sudah order!
š¦ Order: #{{2}}
š° Total: Rp {{3}}
Pesanan sedang diproses dan akan dikirim dalam 1-2 hari.
Butuh bantuan? Reply pesan ini!Shipping Notification:
š¦ Pesanan Dikirim!
Hai {{1}}, order #{{2}} sudah dikirim!
š Kurir: {{3}}
š Resi: {{4}}
š
Estimasi: {{5}}
Track di: {{6}}Payment Reminder:
ā° Reminder Pembayaran
Hai {{1}},
Order #{{2}} menunggu pembayaran.
š° Total: Rp {{3}}
ā³ Batas bayar: {{4}}
Bayar sekarang agar pesanan segera diproses!Appointment Reminder:
š
Reminder Jadwal
Hai {{1}},
Ini reminder untuk jadwal kamu:
š {{2}}
š
{{3}}
ā° {{4}}
Sampai jumpa!Best Practices
DO ā
- Buat template untuk semua use case
- Test sebelum production
- Monitor quality score
- A/B test marketing templates
- Update berkala
- Simpan backup template textDON'T ā
- Kirim tanpa template (business-initiated)
- Terlalu banyak variables
- Copy template kompetitor
- Ignore rejection feedback
- Spam marketing templates
- Skip example valuesFAQ
Berapa lama approval?
5 menit - 24 jam. Biasanya beberapa jam. Marketing bisa lebih lama.
Template rejected, gimana?
Baca alasan, perbaiki, submit ulang. Atau appeal jika merasa benar.
Bisa edit template yang sudah approved?
Tidak. Harus buat template baru dengan nama berbeda.
Kesimpulan
Template = Kunci business messaging!
| Tanpa Template | Dengan Template |
|---|---|
| Tidak bisa broadcast | Bisa broadcast |
| Hanya reply | Bisa initiate |
| Limited | Full feature |