Chatera Docs
API & Integrasi

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/templates

Scope yang dibutuhkan: whatsapp:templates

Endpoint ini mengembalikan daftar template yang sudah tersinkron dari Meta Business Manager dan siap dipakai (status APPROVED).

Query paramWajibKeterangan
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 }
}
FieldTipeKeterangan
idstring (UUID)Identifier internal Chatera — bukan untuk body template.name
namestringNama template di Meta. Ini yang dipakai saat kirim
categorystringAUTHENTICATION / MARKETING / UTILITY
statusstringSelalu APPROVED di endpoint ini
languages[]arrayBahasa yang tersedia: { code, status }. Pakai code yang ber-status APPROVED sebagai template.language.code saat kirim
components[]arrayStruktur template dari Meta: HEADER/BODY/FOOTER/BUTTONS. Variabel posisional tampil sebagai {{1}}, {{2}}, dst. di text
channel_idstring (UUID)Channel pemilik template — kirim channel_id yang sama di POST /messages supaya template pasti tersedia di nomor tujuan
created_at / updated_atstringTimestamp sinkronisasi

Mengirim template

Ada dua cara mengirim template — gunakan endpoint /messages untuk konsistensi.

POST /v1/whatsapp/messages

Scope: whatsapp:send

Body memakai type: template dan field template:

{
  "to": "628123456789",
  "type": "template",
  "template": {
    "name": "otp_verification",
    "language": { "code": "id" },
    "components": [...]
  }
}
FieldWajibKeterangan
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.componentstergantung templateKomponen 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}/send

Scope: 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" }] }
    ]
  }'
FieldWajibKeterangan
{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
componentstergantung templateSama 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:

typeFungsiParameter yang valid
headerMedia / lokasi di header pesantext, image, video, document, location
bodyVariabel di bodytext, currency, date_time
buttonVariabel 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_offerWaktu kedaluwarsa penawaran terbatas (template LTO)limited_time_offer
carouselKartu-kartu carousel media. Isinya cards[], bukan parameters— (tiap kartu punya components sendiri: header, body, button)

Tipe parameter khusus:

Tipe parameterBentukKeterangan
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" }]
      }
    ]
  }
}
  • index adalah posisi tombol (0-based).
  • payload dikirim 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.

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" }]
              }
            ]
          }
        ]
      }
    ]
  }
}
FieldWajibTipeKeterangan
cards✅arrayDaftar kartu, maks 10 (template di Meta minimal 2 kartu)
cards[].card_index✅numberPosisi kartu, 0-based dan unik per carousel
cards[].components✅arrayKomponen 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

KodePenyebabSolusi
WHATSAPP_TEMPLATE_NOT_FOUNDNama template tidak ditemukan / belum approvedCek nama dan status di Meta Business Manager
WHATSAPP_TEMPLATE_REJECTEDTemplate ditolak MetaPerbaiki konten template di Meta lalu submit ulang
WHATSAPP_TEMPLATE_INVALID_COMPONENTSStruktur components tidak validLihat details.errors[]
WHATSAPP_TEMPLATE_MISSING_BUTTON_INDEXKomponen button tidak punya indexTambahkan index: 0 (atau 1, 2, dst sesuai posisi)
WHATSAPP_TEMPLATE_INVALID_PARAMETER_TYPETipe parameter tidak cocok dengan komponenMis. currency di komponen header (tidak diperbolehkan)
WHATSAPP_SEND_FAILEDMeta menolak requestBaca 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:

  1. Salah language.code — template dibuat dengan bahasa en tapi kamu kirim id (atau sebaliknya). Cocokkan dengan languages[].code di response list.
  2. Salah channel — template terdaftar di channel/nomor lain. Kirim channel_id yang sama dengan channel_id template di response list.
  3. 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.

On this page