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.
Semua path di halaman ini relatif terhadap base URL https://api.chatera.id/v1.
Membuat template dari dashboard
Template dibuat di menu Template WhatsApp di dashboard Chatera. Builder-nya mendukung tombol kode kupon, penawaran terbatas (LTO), carousel kartu media, header lokasi, OTP dengan zero-tap, dan Dari pustaka Meta (Meta Template Library — template UTILITY siap pakai buatan Meta, tetap melewati review tapi isinya sudah sesuai pedoman). Semuanya bisa dipakai walau bisnis kamu belum terverifikasi; batas normal tetap berlaku, yaitu 250 penerima unik per 24 jam untuk template yang dikirim duluan oleh bisnis.
Identitas template: name + language, bukan ID
Pengiriman template selalu memakai template.name + template.language.code
— field id (UUID) di response list hanyalah identifier internal Chatera dan
tidak bisa dipakai di body POST /v1/whatsapp/messages. Nama template
tidak bisa diubah setelah dibuat di Meta, jadi aman dijadikan referensi stabil
di integrasi kamu. (Alternatif: endpoint
POST /v1/whatsapp/templates/{id}/send
menerima UUID.)
List template yang tersedia
GET /v1/whatsapp/templatesScope yang dibutuhkan: whatsapp:templates
Endpoint ini mengembalikan daftar template yang sudah tersinkron dari
Meta Business Manager dan siap dipakai (status APPROVED).
| Query param | Wajib | Keterangan |
|---|---|---|
channel_id | — | UUID channel WhatsApp. Sangat disarankan bila akun punya lebih dari satu channel — tanpa ini dipakai channel aktif terbaru. Channel tidak ditemukan → WHATSAPP_CHANNEL_NOT_FOUND |
page | — | Halaman (default 1) |
per_page | — | Jumlah per halaman |
curl -X GET "https://api.chatera.id/v1/whatsapp/templates" \
-H "Authorization: Bearer chatera_sk_xxxxx"Response list
{
"success": true,
"data": [
{
"id": "9b8c1234-e5f6-4789-90ab-cdef01234567",
"name": "order_confirmation",
"category": "UTILITY",
"status": "APPROVED",
"languages": [
{ "code": "id", "status": "APPROVED" }
],
"components": [
{ "type": "HEADER", "format": "TEXT", "text": "Konfirmasi Order" },
{
"type": "BODY",
"text": "Halo {{1}}, order {{2}} sudah kami terima.",
"example": { "body_text": [["Hafari", "ORD-12345"]] }
},
{ "type": "FOOTER", "text": "Terima kasih." }
],
"channel_id": "1ec6a154-02fa-49f4-bad0-ab9f89a5eb85",
"created_at": "2026-04-27T10:30:00Z",
"updated_at": "2026-04-27T10:30:00Z"
}
],
"meta": { "page": 1, "per_page": 25, "total": 1, "has_more": false }
}| Field | Tipe | Keterangan |
|---|---|---|
id | string (UUID) | Identifier internal Chatera — bukan untuk body template.name |
name | string | Nama template di Meta. Ini yang dipakai saat kirim |
category | string | AUTHENTICATION / MARKETING / UTILITY |
status | string | Selalu APPROVED di endpoint ini |
languages[] | array | Bahasa yang tersedia: { code, status }. Pakai code yang ber-status APPROVED sebagai template.language.code saat kirim |
components[] | array | Struktur template dari Meta: HEADER/BODY/FOOTER/BUTTONS. Variabel posisional tampil sebagai {{1}}, {{2}}, dst. di text |
channel_id | string (UUID) | Channel pemilik template — kirim channel_id yang sama di POST /messages supaya template pasti tersedia di nomor tujuan |
created_at / updated_at | string | Timestamp sinkronisasi |
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) — bukan UUID dari list |
template.language.code | ✅ | Kode bahasa persis seperti saat template dibuat di Meta, mis. id, en, en_US. Lihat languages[].code di response list — kode yang salah menghasilkan error Meta #132001 |
template.components | tergantung template | Komponen yang berisi parameter dinamis |
channel_id | — | UUID channel WhatsApp pengirim. Wajib bila punya lebih dari satu channel aktif (tanpa ini request ditolak VALIDATION_MISSING_FIELD) — pakai channel_id yang sama dengan yang muncul di response list supaya template pasti terdaftar di nomor pengirim |
Kirim lewat endpoint template
Alternatif dari /messages: endpoint ini menerima UUID template Chatera
(dari response list) atau nama template di path.
POST /v1/whatsapp/templates/{templateId}/sendScope: whatsapp:send
curl -X POST "https://api.chatera.id/v1/whatsapp/templates/9b8c1234-e5f6-4789-90ab-cdef01234567/send" \
-H "Authorization: Bearer chatera_sk_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"to": "628123456789",
"components": [
{ "type": "body", "parameters": [{ "type": "text", "text": "Hafari" }] }
]
}'| Field | Wajib | Keterangan |
|---|---|---|
{templateId} (path) | ✅ | UUID template dari list, atau langsung nama template |
to | ✅ | Nomor tujuan E.164 |
language | — | Kode bahasa. Bila templateId UUID dan field ini kosong, otomatis dipakai bahasa translation yang APPROVED; bila pakai nama template, default id |
components | tergantung template | Sama seperti template.components di /messages |
channel_id | — | Override channel pengirim. Bila kosong dan templateId UUID, otomatis dipakai channel pemilik template |
Kelebihan jalur UUID: nama, bahasa, dan channel di-resolve dari data template
tersimpan — menghilangkan dua penyebab paling umum error #132001
(salah language.code dan salah channel).
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 / kode kupon) | text (untuk sub_type: url), payload (untuk sub_type: quick_reply), coupon_code (untuk sub_type: copy_code) |
limited_time_offer | Waktu kedaluwarsa penawaran terbatas (template LTO) | limited_time_offer |
carousel | Kartu-kartu carousel media. Isinya cards[], bukan parameters | — (tiap kartu punya components sendiri: header, body, button) |
Tipe parameter khusus:
| Tipe parameter | Bentuk | Keterangan |
|---|---|---|
payload | { "type": "payload", "payload": "beli_1" } | Dikirim balik ke webhook saat tombol quick reply ditekan |
coupon_code | { "type": "coupon_code", "coupon_code": "HEMAT20" } | Kode yang disalin pelanggan lewat tombol Salin kode, maks 20 karakter |
limited_time_offer | { "type": "limited_time_offer", "limited_time_offer": { "expiration_time_ms": 1767225600000 } } | Waktu berakhir penawaran dalam Unix milidetik |
Variabel bernama (`parameter_name`)
Template yang dibuat dengan variabel bernama (mis. {{nama}}, bukan
{{1}}) wajib menyertakan parameter_name di setiap parameter teks:
{ "type": "text", "parameter_name": "nama", "text": "Budi" }.
Template dengan variabel posisional ({{1}}, {{2}}) cukup mengirim
parameter sesuai urutan, tanpa parameter_name. Lihat contoh #3.
Contoh-contoh
1. Template OTP (AUTHENTICATION)
Template kategori AUTHENTICATION punya tombol salin kode / isi otomatis
(termasuk zero-tap). Kode OTP wajib dikirim dua kali: di body
dan di komponen button (sub_type: "url", index: 0).
{
"to": "628123456789",
"type": "template",
"template": {
"name": "otp_verification",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "482913" }
]
},
{
"type": "button",
"sub_type": "url",
"index": 0,
"parameters": [
{ "type": "text", "text": "482913" }
]
}
]
}
}Jangan kirim OTP hanya di body
Kalau komponen button dihilangkan, Chatera tetap meneruskan request,
tetapi Meta menolaknya dan kamu menerima WHATSAPP_SEND_FAILED.
Pastikan nilai kode di body dan button sama persis.
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.
8. Template kode kupon (MARKETING)
Template MARKETING dengan tombol Salin kode. Kirim kodenya lewat
sub_type: "copy_code"; index mengikuti posisi tombol di template.
{
"to": "628123456789",
"type": "template",
"template": {
"name": "promo_kupon",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Budi" }
]
},
{
"type": "button",
"sub_type": "copy_code",
"index": 0,
"parameters": [
{ "type": "coupon_code", "coupon_code": "HEMAT20" }
]
}
]
}
}coupon_code maksimal 20 karakter — lebih dari itu ditolak dengan
WHATSAPP_TEMPLATE_INVALID_COMPONENTS.
9. Template penawaran terbatas / LTO (MARKETING)
Template limited-time offer menampilkan hitung mundur sampai penawaran
berakhir. Kirim waktu berakhirnya lewat komponen limited_time_offer
(Unix milidetik). Biasanya dipasangkan dengan tombol salin kode.
{
"to": "628123456789",
"type": "template",
"template": {
"name": "flash_sale_lto",
"language": { "code": "id" },
"components": [
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "link": "https://toko-anda.com/promo/flash-sale.jpg" } }
]
},
{
"type": "limited_time_offer",
"parameters": [
{
"type": "limited_time_offer",
"limited_time_offer": { "expiration_time_ms": 1767225600000 }
}
]
},
{
"type": "button",
"sub_type": "copy_code",
"index": 0,
"parameters": [
{ "type": "coupon_code", "coupon_code": "FLASH50" }
]
},
{
"type": "button",
"sub_type": "url",
"index": 1,
"parameters": [
{ "type": "text", "text": "flash-sale" }
]
}
]
}
}Batasan template LTO
- Hanya kategori MARKETING dan tidak boleh punya footer.
- Teks body maksimal 600 karakter (bukan 1024 seperti template biasa).
- Header opsional, hanya gambar atau video. Tombol salin kode opsional dengan kode maksimal 15 karakter, ditambah tombol URL.
- Hitung mundur penawaran tidak tampil di WhatsApp Web / Desktop — pelanggan di sana tetap menerima isi pesannya.
10. Template carousel kartu media (MARKETING)
Carousel berisi 2–10 kartu yang bisa digeser. Setiap kartu punya
header media (gambar/video), teks kartu opsional (maks 160 karakter,
boleh berisi variabel), dan 0–2 tombol (balasan cepat, URL, atau
telepon). Semua kartu wajib memakai jenis media dan susunan tombol yang
sama; bila satu kartu punya teks, semua kartu wajib punya teks. Kirim satu komponen
carousel berisi cards[]:
{
"to": "628123456789",
"type": "template",
"template": {
"name": "katalog_carousel",
"language": { "code": "id" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Budi" }
]
},
{
"type": "carousel",
"cards": [
{
"card_index": 0,
"components": [
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "id": "1234567890123456" } }
]
},
{
"type": "button",
"sub_type": "quick_reply",
"index": 0,
"parameters": [{ "type": "payload", "payload": "beli_1" }]
},
{
"type": "button",
"sub_type": "url",
"index": 1,
"parameters": [{ "type": "text", "text": "produk-1" }]
}
]
},
{
"card_index": 1,
"components": [
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "id": "6543210987654321" } }
]
},
{
"type": "button",
"sub_type": "quick_reply",
"index": 0,
"parameters": [{ "type": "payload", "payload": "beli_2" }]
},
{
"type": "button",
"sub_type": "url",
"index": 1,
"parameters": [{ "type": "text", "text": "produk-2" }]
}
]
}
]
}
]
}
}| Field | Wajib | Tipe | Keterangan |
|---|---|---|---|
cards | ✅ | array | Daftar kartu, maks 10 (template di Meta minimal 2 kartu) |
cards[].card_index | ✅ | number | Posisi kartu, 0-based dan unik per carousel |
cards[].components | ✅ | array | Komponen kartu: header (media), body (bila kartu punya variabel), button |
Setiap kartu wajib punya header media
Meta mewajibkan parameter header (gambar atau video) di setiap
kartu, termasuk kartu yang tidak punya variabel lain. Jumlah kartu
yang dikirim harus sama dengan jumlah kartu di template.
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 | Baca details.error — berisi pesan error asli dari Meta (lihat contoh di bawah) |
Detail error contoh
Validasi komponen (dari Chatera, sebelum request ke Meta):
{
"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)"
}
]
}
}
}Penolakan dari Meta (WHATSAPP_SEND_FAILED) — pesan asli Meta diteruskan
apa adanya di details.error:
{
"success": false,
"error": {
"code": "WHATSAPP_SEND_FAILED",
"message": "Failed to send WhatsApp message",
"details": {
"error": "(#132001) Template name does not exist in the translation"
}
}
}Troubleshooting #132001
Error Meta (#132001) Template name does not exist in the translation
artinya kombinasi nama + bahasa + nomor pengirim tidak menemukan
template. Tiga penyebab paling umum, urut dari yang paling sering:
- Salah
language.code— template dibuat dengan bahasaentapi kamu kirimid(atau sebaliknya). Cocokkan denganlanguages[].codedi response list. - Salah channel — template terdaftar di channel/nomor lain. Kirim
channel_idyang sama denganchannel_idtemplate di response list. - Template sudah tidak ada di Meta — mis. nomor lama dilepas/diblokir. Lakukan sinkronisasi ulang template dari dashboard; template yang sudah hilang di Meta akan dinonaktifkan otomatis dari list.