Kirim satu pesan
POST /api/messages, izin write:messages. Satu pesan ke satu pelanggan WhatsApp, dijawab dengan id pesan yang terbentuk. Cocok untuk pengingat janji, status pesanan, atau hasil laboratorium yang dikirim dari sistem Anda.
Pesan berupa salah satu dari dua bentuk:
- template yang sudah disetujui Meta, bisa dikirim kapan saja;
- teks bebas, hanya bila pelanggan mengirim pesan dalam 24 jam terakhir.
Contoh permintaan
- cURL
- Python
- Node.js
- PHP
curl -X POST https://kareeb.id/api/messages \
-H "Authorization: Bearer kt_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"to": "6281234567890",
"template": {
"name": "pengingat_kontrol",
"language": "id",
"body_params": {"1": "Budi", "2": "Rumah Sakit Sentra", "3": "Selasa 10.00"}
},
"idempotency_key": "janji-88123-h1"
}'
import httpx
r = httpx.post(
"https://kareeb.id/api/messages",
headers={"Authorization": "Bearer kt_xxxxxxxxxxxxxxxxxxxx"},
json={
"to": "6281234567890",
"template": {
"name": "pengingat_kontrol",
"language": "id",
"body_params": {"1": "Budi", "2": "Rumah Sakit Sentra", "3": "Selasa 10.00"},
},
"idempotency_key": "janji-88123-h1",
},
timeout=30,
)
print(r.status_code, r.json())
const res = await fetch("https://kareeb.id/api/messages", {
method: "POST",
headers: {
"Authorization": "Bearer kt_xxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "6281234567890",
template: {
name: "pengingat_kontrol",
language: "id",
body_params: { "1": "Budi", "2": "Rumah Sakit Sentra", "3": "Selasa 10.00" },
},
idempotency_key: "janji-88123-h1",
}),
});
console.log(res.status, await res.json());
$ch = curl_init("https://kareeb.id/api/messages");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer kt_xxxxxxxxxxxxxxxxxxxx",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"to" => "6281234567890",
"template" => [
"name" => "pengingat_kontrol",
"language" => "id",
"body_params" => ["1" => "Budi", "2" => "Rumah Sakit Sentra", "3" => "Selasa 10.00"],
],
"idempotency_key" => "janji-88123-h1",
]),
]);
$body = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $body;
Untuk teks bebas, ganti template dengan text:
{
"contact_id": 88,
"text": "Halo Budi, hasil laboratorium Anda sudah bisa diambil.",
"idempotency_key": "lab-88-2026-11-04"
}
Isi permintaan
Isi tepat satu dari to atau contact_id, dan tepat satu dari text atau template. Mengisi keduanya atau tidak mengisi keduanya dijawab 422.
| Kolom | Wajib | Keterangan |
|---|---|---|
to | salah satu dari to / contact_id | Nomor WhatsApp tujuan, format internasional, 7 sampai 20 digit. Tanda plus di depan dan spasi di tepi dibuang. Nomor yang belum dikenal Kareeb otomatis menjadi kontak baru. |
contact_id | salah satu dari to / contact_id | Id kontak di cabang pengirim. |
text | salah satu dari text / template | Teks bebas, 1 sampai 4.096 karakter. |
template.name | bila memakai template | Nama template yang sudah disetujui dan ada di akun WhatsApp cabang pengirim. |
template.language | tidak | Kode bahasa template. Bawaan "id". |
template.body_params | tidak | Isi variabel badan, kunci "1" sampai "N" tanpa celah. Lihat Daftar template. |
template.cta_param | bila template punya tombol tautan per pelanggan | Bagian akhir alamat yang ditempel ke tautan tombol. |
idempotency_key | ya | Teks unik per pesan, 1 sampai 128 karakter, unik di organisasi Anda. Lihat Kirim ulang tanpa pesan ganda. |
workspace_id | tidak | Cabang pengirim, harus milik organisasi Anda. Bawaan: cabang Utama. |
Jawaban
201 Created untuk kiriman baru, 200 OK bila kunci yang sama sudah pernah dikirim.
{
"message_id": 9137,
"conversation_id": 412,
"wa_message_id": "wamid.HBgM...",
"contact_id": 88,
"replay": false
}
Jawaban 201 berarti Meta sudah menerima pesan dari Kareeb. Sampai atau tidaknya ke ponsel pelanggan dilaporkan kemudian lewat webhook message.status dengan wa_message_id yang sama (lihat Webhook). Simpan wa_message_id di sistem Anda.
Urutan pemeriksaan
Kareeb memeriksa permintaan dengan urutan ini dan berhenti pada penolakan pertama:
- Batas permintaan. Setiap panggilan dihitung per token, termasuk yang ditolak dan kiriman ulang. Bila terlalu banyak, jawabannya
429: tunggu sebanyak detik di headerRetry-After. - Kunci. Kunci yang sudah pernah dipakai dijawab
200dengan id pesan pertama dan"replay": true. Tidak ada yang dikirim lagi. - Cabang.
workspace_iddi luar organisasi Anda dijawab404. - Tujuan.
contact_idharus kontak cabang itu (404);toharus nomor WhatsApp (422); kontaknya harus kontak WhatsApp (422). - Berhenti berlangganan. Pelanggan yang sudah meminta berhenti dikirimi pesan ditolak, untuk teks maupun template (
422). Bila memang harus dihubungi, lakukan lewat operator. - Teks: jendela 24 jam harus terbuka (
409). Template: sudah disinkronkan, ada di akun WhatsApp cabang ini, berstatusAPPROVED, variabelnya valid, dancta_paramterisi bila template punya tombol tautan. TemplateMARKETINGjuga butuh persetujuan promosi dari pelanggan bila instalasi Kareeb Anda mewajibkannya. - Pengiriman lewat jalur yang sama dengan semua pesan Kareeb. Organisasi yang dinonaktifkan atau berstatus baca saja ditolak di sini, dan penolakan dari Meta dikembalikan seperti di kotak masuk.
Kode penolakan
Penolakan membawa detail berupa objek. Bercabanglah pada code; kalimat di message ditulis untuk dibaca orang dan bisa diubah kapan saja.
{"detail": {"code": "window_closed", "message": "..."}}
| HTTP | code | Arti dan yang perlu dilakukan |
|---|---|---|
404 | cabang_not_found | workspace_id bukan cabang organisasi ini. Periksa id cabang. |
404 | contact_not_found | contact_id bukan kontak cabang ini. Periksa id kontak. |
409 | window_closed | Teks di luar jendela 24 jam. Kirim template. |
422 | invalid_phone | to bukan 7 sampai 20 digit. |
422 | channel_unsupported | Kontak ada di Instagram, Messenger, atau WhatsApp Lite. Endpoint ini hanya untuk WhatsApp Cloud API. |
422 | opted_out | Pelanggan sudah meminta berhenti dikirimi pesan. |
422 | consent_required | Template MARKETING ke pelanggan yang belum menyetujui promosi, pada instalasi yang mewajibkan persetujuan. |
422 | template_not_synced | Template belum ada di Kareeb. Admin menekan Sinkronkan di menu Template, lalu kirim lagi. |
422 | template_other_account | Template hanya ada di akun WhatsApp yang tidak lagi dipakai organisasi ini. |
422 | template_other_cabang | Template ada di akun WhatsApp cabang lain. Kirim dengan workspace_id cabang itu. |
422 | template_not_approved | Template belum disetujui Meta (PENDING, REJECTED, PAUSED). Mengulang tidak membantu; tunggu persetujuan Meta. |
422 | invalid_params | Kunci atau nilai body_params yang akan ditolak WhatsApp. |
422 | template_needs_cta | Template punya tombol tautan per pelanggan dan cta_param kosong. |
429 | rate_limited | Terlalu banyak permintaan. Tunggu Retry-After, lalu ulangi dengan kunci yang sama. |
Badan yang tidak sesuai bentuk di atas dijawab 422 oleh FastAPI dengan daftar galat per kolom. Token tanpa izin write:messages dijawab 403 yang menyebut nama izinnya.
Aturan yang perlu diingat
- Hanya WhatsApp Cloud API. Kontak Instagram, Messenger, dan WhatsApp Lite ditolak.
- Pesan dari API tercatat tanpa nama pengirim di Kareeb, ditandai sebagai kiriman API, dan tidak mengambil alih percakapan dari Agen AI.
- Template UTILITY (pengingat, status pesanan) tidak butuh persetujuan promosi. Template MARKETING butuh, bila instalasi mewajibkannya.