Dokumentasi API
Halaman ini menjelaskan cara memakai endpoint api.php
dan kirim.php untuk mengirim & menerima pesan
WhatsApp lewat hosting ini. Endpoint ini dipakai oleh local app (yang benar-benar
terhubung ke WhatsApp) dan bisa juga dipanggil dari sistem eksternal untuk menitip pesan keluar.
1. Autentikasi
Semua endpoint kecuali webhook wajib mengirim header:
X-API-Secret: <isi API_SECRET dari .env>
Kalau header tidak ada → 401. Kalau isinya salah →
403. Nilai ini harus sama persis dengan
API_SECRET di .env
(lihat halaman Admin untuk cek beberapa karakter pertama/terakhirnya).
Endpoint webhook memakai token yang berbeda
(WEBHOOK_TOKEN), dikirim lewat parameter
token di query string atau body — supaya kalau token ini bocor,
penyerang cuma bisa menitip pesan ke outbox, tidak bisa mengakses endpoint lain.
POST kirim.php (disarankan untuk aplikasi luar)
File terpisah dari api.php, khusus untuk dipanggil dari
aplikasi/sistem pihak ketiga yang ingin mengirim pesan WhatsApp. Parameternya hampir sama persis dengan form
Tes Kirim Pesan di dashboard — bedanya, di sini Device ID tidak perlu dikirim manual.
company_devices.token), yang ditampilkan
sekali di halaman dashboard dan bisa dibuat ulang kapan saja. Token inilah yang dipakai untuk
autentikasi di sini — device_id tujuan
otomatis ditentukan dari token, tidak perlu dikirim terpisah. WEBHOOK_TOKEN
di .env tidak dipakai lagi di sini (masih dipakai khusus untuk action=webhook versi lama).
Catatan: karena ini pesan keluar, nomor tujuan tidak otomatis dicatat sebagai kontak — pencatatan kontak hanya terjadi untuk chat masuk (lihat Pencatatan kontak).
| Field | Wajib | Keterangan |
|---|---|---|
| token | Ya | Token unik device, didapat dari dashboard perusahaan saat device didaftarkan (atau setelah "Buat Ulang Token"). Menentukan device_id tujuan secara otomatis |
| to_number | Ya | Nomor tujuan (boleh format 08xx, otomatis dinormalisasi ke 62xx) |
| message_text | Salah satu wajib* | Isi pesan / caption media |
| media_file | Tidak | Upload file langsung (multipart/form-data) — gambar/video/dokumen, maks 20MB. Kalau diisi, media_url/media_mimetype/media_filename di bawah diabaikan |
| media_url | Salah satu wajib* | Alternatif kalau file sudah ada di URL publik (tidak upload langsung) |
| media_mimetype | Tidak | Mimetype media, mis. image/jpeg (dipakai bersama media_url) |
| media_filename | Tidak | Nama file media (dipakai bersama media_url) |
*Minimal salah satu dari message_text, media_file, atau media_url harus diisi.
Contoh 1 — kirim pesan teks saja:
curl -s -X POST "https://crm.kiosq.id/kirim.php" \
-d "token=TOKEN_DEVICE_ANDA" \
-d "to_number=081234567890" \
-d "message_text=Halo dari aplikasi luar"
Contoh 2 — upload file media langsung (multipart):
curl -s -X POST "https://crm.kiosq.id/kirim.php" \
-F "token=TOKEN_DEVICE_ANDA" \
-F "to_number=081234567890" \
-F "message_text=Cek lampiran ya" \
-F "media_file=@/path/ke/file.jpg"
Contoh 3 — pakai media yang sudah ada di URL publik:
curl -s -X POST "https://crm.kiosq.id/kirim.php" \
-d "token=TOKEN_DEVICE_ANDA" \
-d "to_number=081234567890" \
-d "media_url=https://domain-anda.com/file.pdf" \
-d "media_mimetype=application/pdf" \
-d "media_filename=invoice.pdf"
Respons sukses — pesan langsung masuk ke tabel wa_messages dengan status pending, menunggu local app mengambil & mengirimnya:
{ "ok": true, "id": 103, "status": "pending" }
Respons gagal (parameter kurang / token salah / dll), selalu dalam format JSON dengan kode HTTP sesuai (lihat tabel error):
{ "error": "to_number, dan message_text/media_file/media_url wajib diisi" }
Kalau token tidak dikenali:
{ "error": "invalid token" }
GET action=pending
Dipakai local app untuk mengambil (dan langsung meng-klaim) pesan outbox yang berstatus pending untuk satu device.
| Parameter | Wajib | Keterangan |
|---|---|---|
| session / device | Ya | Device ID (mis. A1B2C3) |
| limit | Tidak | Jumlah maksimal pesan diambil sekali panggil (default 10, maks 50) |
curl -s "https://crm.kiosq.id/api.php?action=pending&session=A1B2C3&limit=10" \
-H "X-API-Secret: SECRET_ANDA"
Respons (pesan langsung berubah status jadi processing begitu diambil, supaya tidak diambil dobel):
{
"items": [
{
"id": 101,
"to_number": "6281234567890",
"message_text": "Halo dari hosting",
"media_url": null,
"media_mimetype": null,
"media_filename": null
}
]
}
POST action=report
Dipakai local app untuk melaporkan hasil pengiriman satu pesan yang sudah diambil lewat pending.
| Parameter | Wajib | Keterangan |
|---|---|---|
| session / device | Ya (query string) | Device ID |
Body JSON:
| Field | Wajib | Keterangan |
|---|---|---|
| id | Ya | ID pesan (dari respons pending) |
| status | Ya | sent atau failed |
| wa_message_id | Tidak | ID pesan dari WhatsApp (untuk pelacakan status lanjutan) |
| chat_jid | Tidak | JID chat WhatsApp tujuan |
| error | Tidak | Pesan error kalau status=failed |
curl -s -X POST "https://crm.kiosq.id/api.php?action=report&session=A1B2C3" \
-H "X-API-Secret: SECRET_ANDA" \
-H "Content-Type: application/json" \
-d '{"id":101,"status":"sent","wa_message_id":"3EB0...","chat_jid":"6281234567890@s.whatsapp.net"}'
POST action=push
Dipakai local app untuk mengirim pesan masuk (chat baru dari lawan bicara) atau update status pengiriman (terkirim/sampai/dibaca) ke hosting.
| Field body | Wajib | Keterangan |
|---|---|---|
| message_id | Ya | ID unik pesan dari WhatsApp |
| chat_jid | Ya | JID chat |
| direction | Tidak | in (default) atau out |
| from_me | Tidak | true/false — menentukan status awal (sent/received) |
| wa_status | Tidak | Angka 0-5 (lihat tabel status WA di bawah) |
| sender_number, recipient_number, push_name | Tidak | Info pengirim. Kalau direction=in, sender_number + push_name otomatis dicatat sebagai kontak baru (lihat Pencatatan kontak) |
| message_type, message_text | Tidak | Jenis & isi pesan |
| is_group | Tidak | Boolean (true/false) -- tandai apakah chat ini dari grup WhatsApp. Kalau tidak dikirim, otomatis dideteksi dari akhiran chat_jid (@g.us = grup, @s.whatsapp.net = pribadi) -- kirim eksplisit kalau local app sudah tahu pasti |
| media_base64, media_mimetype, media_filename | Tidak | Media di-encode base64 untuk disimpan di database |
| media_truncated | Tidak | true kalau media dipotong karena kebesaran |
| wa_timestamp | Tidak | Unix timestamp pesan dari WhatsApp |
curl -s -X POST "https://crm.kiosq.id/api.php?action=push&session=A1B2C3" \
-H "X-API-Secret: SECRET_ANDA" \
-H "Content-Type: application/json" \
-d '{
"message_id": "3EB0...",
"chat_jid": "6281234567890@s.whatsapp.net",
"direction": "in",
"sender_number": "6281234567890",
"push_name": "Budi",
"message_type": "text",
"message_text": "Halo, ini balasan dari pelanggan",
"is_group": false
}'
Tabel kode wa_status:
| Nilai | Arti |
|---|---|
| 0 | Error |
| 1 | Pending |
| 2 | Terkirim ke server WhatsApp |
| 3 | Sampai di HP tujuan |
| 4 | Sudah dibaca |
| 5 | Voice note diputar |
contacts,
dipakai untuk fitur Blast Pesan) hanya dari chat masuk —
yaitu hit action=push dengan direction=in.
Nomor tujuan dari pesan keluar (kirim.php,
action=webhook, atau action=push
dengan direction=out) tidak dicatat sebagai kontak.
Nama kontak diisi dari push_name, dan sekali tersimpan tidak akan ditimpa.
GET POST action=webhook (versi lama, masih didukung)
Fungsinya sama dengan kirim.php
di atas (masuk ke outbox lewat token WEBHOOK_TOKEN), tapi lewat
api.php dan tidak mendukung upload file langsung
(hanya media_url). Untuk integrasi baru, disarankan pakai
kirim.php. Sama seperti kirim.php,
ini pesan keluar sehingga nomor tujuan tidak dicatat sebagai kontak.
Endpoint untuk pihak eksternal (Zapier, sistem lain) menitip pesan ke outbox tanpa perlu header custom — cukup token di query string atau body, supaya kompatibel dengan tool yang tidak bisa kirim header sendiri.
| Field | Wajib | Keterangan |
|---|---|---|
| token | Ya | Harus sama dengan WEBHOOK_TOKEN di .env |
| device_id | Ya | Device ID tujuan |
| to_number / to | Ya | Nomor tujuan (boleh format 08xx, otomatis dinormalisasi ke 62xx) |
| message_text / message / text | Salah satu wajib* | Isi pesan |
| media_url | Salah satu wajib* | URL media publik yang mau dikirim |
| media_mimetype, media_filename | Tidak | Metadata media |
*Minimal salah satu dari message_text atau media_url harus diisi.
curl -s -X POST "https://crm.kiosq.id/api.php?action=webhook" \
-H "Content-Type: application/json" \
-d '{
"token": "WEBHOOK_TOKEN_ANDA",
"device_id": "A1B2C3",
"to_number": "081234567890",
"message_text": "Halo dari sistem eksternal"
}'
Atau lewat GET (query string), cocok untuk tool yang cuma bisa hit URL:
https://crm.kiosq.id/api.php?action=webhook&token=WEBHOOK_TOKEN_ANDA&device_id=A1B2C3&to_number=081234567890&message=Halo
Respons sukses:
{ "ok": true, "id": 102 }
GET action=media
Mengambil isi file media (gambar/video/dokumen) yang tersimpan di database, mis. untuk ditampilkan di aplikasi lain.
| Parameter | Wajib | Keterangan |
|---|---|---|
| session / device | Ya | Device ID |
| id | Ya | ID baris pesan (kolom id) |
curl -s "https://crm.kiosq.id/api.php?action=media&session=A1B2C3&id=101" \
-H "X-API-Secret: SECRET_ANDA" \
-o file-hasil.jpg
Respons berupa file binari langsung (bukan JSON), dengan header Content-Type & Content-Disposition sesuai media aslinya.
POST action=log
Dipakai local app untuk mengirim log status/aktivitas device ke hosting — mis. koneksi WhatsApp putus,
berhasil reconnect, error saat kirim, QR code discan ulang, dsb. Log ini terpisah dari
riwayat pesan (wa_messages) dan bisa
dilihat perusahaan lewat halaman Log Device di dashboard mereka.
| Parameter | Wajib | Keterangan |
|---|---|---|
| session / device | Ya (query string) | Device ID |
Body JSON:
| Field | Wajib | Keterangan |
|---|---|---|
| message | Ya | Isi log (maks 5000 karakter, dipotong otomatis kalau lebih) |
| level | Tidak | debug / info (default) / warn / error. Nilai lain otomatis jadi info |
| context | Tidak | Object bebas untuk detail tambahan (disimpan sebagai JSON), mis. {"attempt":2,"reason":"timeout"} |
curl -s -X POST "https://crm.kiosq.id/api.php?action=log&session=A1B2C3" \
-H "X-API-Secret: SECRET_ANDA" \
-H "Content-Type: application/json" \
-d '{
"level": "warn",
"message": "Koneksi WhatsApp terputus, mencoba reconnect",
"context": { "attempt": 2, "reason": "timeout" }
}'
Respons sukses:
{ "ok": true }
9. Kode error umum
| Kode | Arti |
|---|---|
| 400 | Parameter/body wajib tidak lengkap atau tidak valid |
| 401 | Header X-API-Secret tidak dikirim |
| 403 | Secret / token salah |
| 404 | Action tidak dikenal, atau media tidak ditemukan |
| 500 | Error internal — cek logs/app.log lewat halaman Admin |
10. Alur kirim pesan end-to-end
- Pesan keluar dibuat: lewat form Tes Kirim Pesan di dashboard perusahaan, atau lewat
kirim.php/action=webhookdari sistem eksternal → masuk ke tabelwa_messagesdenganstatus=pending. - Local app polling
action=pendingsecara berkala → pesan otomatis berubah jadistatus=processingbegitu diambil. - Local app benar-benar mengirim pesan lewat WhatsApp, lalu melapor lewat
action=report→ status akhir jadisentataufailed. - Kalau ada balasan dari pelanggan, atau update status seperti "sudah dibaca", local app kirim lewat
action=push. - Media yang diterima bisa diambil lagi lewat
action=media.
0 diganti jadi
62 (mis. 081234567890 →
6281234567890). Tidak perlu format ini di sisi pengirim.
API_SECRET / WEBHOOK_TOKEN
di tempat publik (repo, chat, dsb). Kalau bocor, ganti segera lewat .env.
11. Bikin script local app (curl + prompt AI)
"Local app" adalah proses yang jalan terus di komputer/server Anda sendiri, terhubung langsung ke
WhatsApp (lewat library semacam whatsapp-web.js
atau Baileys di Node.js), yang secara berkala
polling & push data ke hosting ini lewat api.php.
Dua cara untuk membuatnya:
A. Coba manual dulu pakai curl
Sebelum menulis kode, pastikan alurnya jalan dengan curl langsung dari terminal:
# 1. Cek ada pesan pending untuk device
curl -s "https://crm.kiosq.id/api.php?action=pending&session=A1B2C3&limit=10" \
-H "X-API-Secret: SECRET_ANDA"
# 2. Lapor pesan #101 sudah terkirim
curl -s -X POST "https://crm.kiosq.id/api.php?action=report&session=A1B2C3" \
-H "X-API-Secret: SECRET_ANDA" -H "Content-Type: application/json" \
-d '{"id":101,"status":"sent","chat_jid":"6281234567890@s.whatsapp.net"}'
# 3. Kirim balasan pelanggan yang masuk
curl -s -X POST "https://crm.kiosq.id/api.php?action=push&session=A1B2C3" \
-H "X-API-Secret: SECRET_ANDA" -H "Content-Type: application/json" \
-d '{"message_id":"3EB0...","chat_jid":"6281234567890@s.whatsapp.net","direction":"in","message_text":"Halo"}'
# 4. Lapor device baru saja reconnect
curl -s -X POST "https://crm.kiosq.id/api.php?action=log&session=A1B2C3" \
-H "X-API-Secret: SECRET_ANDA" -H "Content-Type: application/json" \
-d '{"level":"info","message":"Device reconnect berhasil"}'
B. Generate script-nya pakai AI
Salin prompt di bawah ini ke Claude/ChatGPT (atau AI assistant lain) untuk membuatkan script Node.js
lengkap — sudah mencakup semua endpoint (pending,
report,
push,
log). URL API sudah otomatis terisi sesuai
domain hosting ini — tinggal ganti <ISI_DEVICE_ID_SAYA>
dan <ISI_API_SECRET_SAYA> sebelum dikirim.
Buatkan saya script (bahasa: Node.js) yang berjalan terus-menerus (long-running
process / daemon) di komputer lokal saya untuk menjembatani WhatsApp (via
library whatsapp-web.js atau Baileys) dengan REST API hosting berikut:
Base URL API: https://crm.kiosq.id/api.php
Device ID: <ISI_DEVICE_ID_SAYA> # 4-6 karakter, dari dashboard perusahaan
API Secret: <ISI_API_SECRET_SAYA> # header X-API-Secret, dari admin hosting
Script harus melakukan hal-hal berikut dalam loop:
1. POLLING OUTBOX (tiap 3-5 detik):
GET https://crm.kiosq.id/api.php?action=pending&session=<ISI_DEVICE_ID_SAYA>&limit=10
Header: X-API-Secret: <ISI_API_SECRET_SAYA>
-> Ambil array "items". Untuk tiap item, kirim pesan (message_text, dan
kalau ada media_url/media_mimetype/media_filename kirim juga medianya)
lewat WhatsApp ke to_number.
2. LAPOR HASIL KIRIM (setelah tiap pesan selesai dikirim/gagal):
POST https://crm.kiosq.id/api.php?action=report&session=<ISI_DEVICE_ID_SAYA>
Header: X-API-Secret: <ISI_API_SECRET_SAYA>, Content-Type: application/json
Body: { "id": <id item dari langkah 1>, "status": "sent" atau "failed",
"wa_message_id": <id pesan dari WhatsApp jika ada>,
"chat_jid": <JID chat tujuan>,
"error": <pesan error kalau status=failed, null kalau sukses> }
3. TERUSKAN PESAN MASUK (event message dari WhatsApp) & UPDATE STATUS
(event ack/read):
POST https://crm.kiosq.id/api.php?action=push&session=<ISI_DEVICE_ID_SAYA>
Header: X-API-Secret: <ISI_API_SECRET_SAYA>, Content-Type: application/json
Body: { "message_id", "chat_jid", "direction": "in", "from_me": false,
"sender_number", "push_name", "message_type", "message_text",
"wa_status" (0-5, kalau ini update status pesan keluar),
"media_base64"/"media_mimetype"/"media_filename" kalau ada media }
4. KIRIM LOG STATUS DEVICE (saat event penting: connected, disconnected,
reconnecting, error, qr_generated -- JANGAN kirim log tiap detik/polling):
POST https://crm.kiosq.id/api.php?action=log&session=<ISI_DEVICE_ID_SAYA>
Header: X-API-Secret: <ISI_API_SECRET_SAYA>, Content-Type: application/json
Body: { "level": "info"|"warn"|"error"|"debug", "message": "<deskripsi
singkat event>", "context": { ...detail tambahan opsional... } }
Ketentuan tambahan:
- Semua request pakai header X-API-Secret di atas, KECUALI kalau nanti saya
sebutkan endpoint lain yang pakai token per-device (jangan diasumsikan).
- Tangani error jaringan dengan retry + backoff sederhana, jangan sampai
proses polling berhenti total kalau satu request gagal.
- Nomor telepon dari WhatsApp (format 62xxxxxxxxxx@s.whatsapp.net) perlu
diubah ke format polos (62xxxxxxxxxx) sebelum dikirim sebagai
sender_number/recipient_number.
- Simpan konfigurasi (base URL, device ID, secret) di file .env terpisah,
jangan hardcode di source code.
- Tambahkan graceful shutdown (SIGINT/SIGTERM) yang menutup koneksi
WhatsApp dengan bersih.
Tolong buatkan strukturnya modular (terpisah: client WhatsApp, client API
hosting, loop polling) supaya mudah saya modifikasi.
info saat script berhasil connect,
supaya Anda tahu integrasinya jalan tanpa perlu cek terminal terus-menerus.