Template WhatsApp
Kirim template WhatsApp yang sudah disetujui Meta untuk komunikasi di luar jendela 24 jam.
Template WhatsApp adalah pesan pre-approved oleh Meta yang bisa dikirim kapan saja — bahkan ketika kontak belum mengirim pesan ke kamu dalam 24 jam terakhir. Template umumnya dipakai untuk OTP, notifikasi order, reminder pembayaran, dan promo.
List template yang tersedia
GET /v1/whatsapp/templatesScope yang dibutuhkan: whatsapp:templates
Endpoint ini mengembalikan daftar template yang sudah dibuat di
Meta Business Manager dan siap dipakai (status APPROVED).
curl -X GET "https://api.chatera.id/v1/whatsapp/templates" \
-H "Authorization: Bearer chatera_sk_xxxxx"Mengirim template
Ada dua cara mengirim template — gunakan endpoint /messages untuk
konsistensi.
POST /v1/whatsapp/messagesScope: whatsapp:send
Body memakai type: template dan field template:
{
"to": "628123456789",
"type": "template",
"template": {
"name": "otp_verification",
"language": { "code": "id" },
"components": [...]
}
}| Field | Wajib | Keterangan |
|---|---|---|
template.name | ✅ | Nama template (sesuai yang terdaftar di Meta) |
template.language.code | ✅ | Kode bahasa, mis. id, en, en_US |
template.components | tergantung template | Komponen yang berisi parameter dinamis |
Struktur komponen
Komponen template dipisah berdasarkan posisinya di template:
type | Fungsi | Parameter yang valid |
|---|---|---|
header | Media / lokasi di header pesan | text, image, video, document, location |
body | Variabel di body | text, currency, date_time |
button | Variabel tombol (URL dinamis / payload) | text (untuk sub_type: url), payload (untuk sub_type: quick_reply) |
Contoh-contoh
1. Template OTP sederhana
{
"to": "628123456789",
"type": "template",
"template": {
"name": "otp_verification",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "123456" }
]
}
]
}
}2. Template dengan header gambar
{
"to": "628123456789",
"type": "template",
"template": {
"name": "order_confirmation",
"language": { "code": "id" },
"components": [
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "link": "https://toko-anda.com/products/item-1.jpg" } }
]
},
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Pak Hafari" },
{ "type": "text", "text": "ORD-12345" }
]
}
]
}
}3. Template dengan named parameter
Jika template kamu memakai variabel bernama (mis. {{customer_name}}):
{
"to": "628123456789",
"type": "template",
"template": {
"name": "promo_weekly",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "John", "parameter_name": "customer_name" },
{ "type": "text", "text": "50%", "parameter_name": "discount" }
]
}
]
}
}4. Template dengan tombol Quick Reply
{
"to": "628123456789",
"type": "template",
"template": {
"name": "order_status_check",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "ORD-12345" }
]
},
{
"type": "button",
"sub_type": "quick_reply",
"index": 0,
"parameters": [{ "type": "payload", "payload": "track_shipment" }]
},
{
"type": "button",
"sub_type": "quick_reply",
"index": 1,
"parameters": [{ "type": "payload", "payload": "contact_support" }]
}
]
}
}indexadalah posisi tombol (0-based).payloaddikirim ke webhook ketika user menekan tombol.
5. Template dengan tombol URL dinamis
Template dengan URL tombol bernama {{1}}:
URL template di Meta: https://toko-anda.com/order/{{1}}{
"to": "628123456789",
"type": "template",
"template": {
"name": "view_order_details",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "John" }
]
},
{
"type": "button",
"sub_type": "url",
"index": 0,
"parameters": [
{ "type": "text", "text": "ORD-12345" }
]
}
]
}
}Penerima akan melihat tombol yang membuka
https://toko-anda.com/order/ORD-12345.
6. Template dengan header lokasi
{
"to": "628123456789",
"type": "template",
"template": {
"name": "store_location",
"language": { "code": "id" },
"components": [
{
"type": "header",
"parameters": [
{
"type": "location",
"location": {
"latitude": -6.2,
"longitude": 106.816666,
"name": "Toko ABC Cabang Sudirman",
"address": "Jl. Sudirman No. 123, Jakarta"
}
}
]
}
]
}
}7. Template dengan currency
{
"to": "628123456789",
"type": "template",
"template": {
"name": "payment_reminder",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "John" },
{
"type": "currency",
"currency": {
"fallback_value": "Rp 250.000",
"code": "IDR",
"amount_1000": 250000000
}
}
]
}
]
}
}Konversi `amount_1000`
amount_1000 menyimpan nilai dalam unit terkecil × 1000 untuk
menghindari floating-point error:
- IDR (Rupiah): Rp 250.000 →
250000 × 1000 = 250000000 - USD (Dolar): $25,50 →
25.50 × 1000 = 25500 - MYR (Ringgit): RM 99,99 →
99.99 × 1000 = 99990
fallback_value adalah teks tampilan yang dipakai kalau penerima
WhatsApp tidak mendukung format currency native.
Response sukses
{
"success": true,
"data": {
"messageId": "9b8c1234-e5f6-4789-90ab-cdef01234567",
"whatsappMessageId": "wamid.HBgNNjI4MTIz...",
"status": "sent",
"to": "+628123456789",
"template": "order_confirmation",
"timestamp": "2026-04-27T10:30:00Z"
}
}Pesan error template
| Kode | Penyebab | Solusi |
|---|---|---|
WHATSAPP_TEMPLATE_NOT_FOUND | Nama template tidak ditemukan / belum approved | Cek nama dan status di Meta Business Manager |
WHATSAPP_TEMPLATE_REJECTED | Template ditolak Meta | Perbaiki konten template di Meta lalu submit ulang |
WHATSAPP_TEMPLATE_INVALID_COMPONENTS | Struktur components tidak valid | Lihat details.errors[] |
WHATSAPP_TEMPLATE_MISSING_BUTTON_INDEX | Komponen button tidak punya index | Tambahkan index: 0 (atau 1, 2, dst sesuai posisi) |
WHATSAPP_TEMPLATE_INVALID_PARAMETER_TYPE | Tipe parameter tidak cocok dengan komponen | Mis. currency di komponen header (tidak diperbolehkan) |
WHATSAPP_SEND_FAILED | Meta menolak request | Cek details untuk pesan dari Meta |
Detail error contoh
{
"success": false,
"error": {
"code": "WHATSAPP_TEMPLATE_INVALID_COMPONENTS",
"message": "Template components validation failed",
"details": {
"errors": [
{
"field": "components[2].index",
"message": "Button component requires index field (0-based button position)"
}
]
}
}
}