Keamanan & retry
Cara memverifikasi request webhook, aturan sukses, jadwal retry, dan checklist saat webhook tidak masuk.
Siapa pun yang tahu URL webhook Anda bisa mengirim request palsu. Karena itu, setiap request dari CSKU membawa Secret Key Anda di header Authorization. Tolak semua request yang nilainya tidak cocok.
Format request
POST /csku/webhook HTTP/1.1
Host: api.toko-anda.com
Content-Type: application/json
Authorization: 3f9a1c7e5b2d4f6a8c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d9f2a4c6e8b0d1f3a
{"event":"channel.message_in","timestamp":1792041600, ...}
Authorizationberisi Secret Key Anda apa adanya: tanpa awalanBearer, tanpa base64.- Tidak ada header signature atau timestamp terpisah. Verifikasi cukup dengan mencocokkan
Authorization. - Secret Key ada di Pengaturan → Secret Key. Lihat Autentikasi.
Verifikasi Authorization
Bandingkan dengan fungsi constant-time, bukan ==, agar waktu perbandingan tidak membocorkan isi secret.
import crypto from 'node:crypto'
function isFromCsku(header, secret) {
const a = Buffer.from(header || '')
const b = Buffer.from(secret)
return a.length === b.length && crypto.timingSafeEqual(a, b)
}
<?php
$ok = hash_equals(getenv('CSKU_SECRET'), $_SERVER['HTTP_AUTHORIZATION'] ?? '');
import hmac
ok = hmac.compare_digest(request.headers.get("Authorization", ""), SECRET)
ok := subtle.ConstantTimeCompare([]byte(r.Header.Get("Authorization")), secret) == 1
Jika tidak cocok, balas {"success": false} dan jangan proses payload.
Simpan secret di server
Secret Key yang sama dipakai untuk memanggil Public API. Simpan hanya di server (environment variable atau secret manager). Jangan taruh di kode frontend, aplikasi mobile, repository publik, atau log.
Ganti (rotate) secret
Reset Secret Key di Pengaturan → Secret Key (butuh OTP ke email owner). Yang berubah:
- Webhook berikutnya, termasuk retry, langsung memakai secret baru di header
Authorization. - Panggilan Public API dengan secret lama ditolak.
Urutan aman:
- Siapkan server agar sementara menerima secret lama atau baru.
- Reset secret di dashboard, lalu simpan secret baru di server.
- Hapus secret lama dari server.
Aturan sukses
CSKU menganggap pengiriman sukses hanya jika body respons Anda berupa JSON dengan field success bernilai benar:
{ "success": true }
Nilai true, "true", atau 1 diterima. Status HTTP tidak dibaca, jadi 200 dengan body kosong tetap dianggap gagal.
Dianggap gagal:
- Tidak ada respons dalam 30 detik (timeout).
- Koneksi gagal (DNS, TLS, server mati).
- Body bukan JSON, atau field
successtidak ada. successbernilaifalse.
Jadwal retry
Pengiriman yang gagal dicoba ulang otomatis. Total maksimal 4 percobaan:
| Percobaan | Waktu (perkiraan) |
|---|---|
| 1 | Saat event terjadi |
| 2 | Langsung setelah percobaan 1 gagal |
| 3 | Sekitar 30 detik setelah percobaan 2 |
| 4 | Sekitar 30 detik setelah percobaan 3 |
Setelah percobaan ke-4 gagal, event itu dilepas dan tidak dikirim lagi. Jika server Anda mati lebih dari sekitar satu menit, ambil pesan yang terlewat lewat Ambil pesan.
Idempotensi dan urutan
- Deduplikasi dengan
message.id. Event yang sama bisa datang lebih dari sekali, misalnya jika server Anda sudah memproses tetapi respons terlambat. Simpanmessage.idyang sudah diproses dan abaikan duplikat. Jangan pakaitimestamp, karena nilainya berubah di setiap percobaan. - Urutan tidak dijamin. Setiap event dikirim sendiri-sendiri. Retry bisa membuat event lama datang setelah event baru. Jika urutan penting, urutkan di sisi Anda, atau ambil riwayat lewat Ambil pesan.
Respons cepat, proses belakangan
Batas waktu 30 detik termasuk semua yang Anda kerjakan sebelum membalas. Pola yang aman:
- Verifikasi
Authorization. - Simpan payload ke antrean atau database.
- Balas
{"success": true}. - Proses (panggil sistem lain, kirim notifikasi) di background job.
Checklist jika webhook tidak masuk
- Paket Anda masih punya fitur Webhook dan masih aktif. Lihat Berlangganan & kredit.
- URL di Pengaturan → Webhook benar, memakai
https, dan bisa diakses dari internet (bukanlocalhostatau IP privat). - Sertifikat TLS server valid dan tidak kedaluwarsa.
- Firewall atau WAF (misalnya proteksi bot) tidak memblokir request
POSTdari server CSKU. - Server membaca header
Authorizationdengan benar. Di Apache + PHP, header ini kadang tidak diteruskan. - Secret di server sama dengan Secret Key terbaru. Jika Anda baru reset, perbarui juga di server.
- Respons Anda berupa JSON
{"success": true}, bukan teks atau body kosong. - Respons dikirim dalam waktu kurang dari 30 detik.
- Event yang Anda tunggu memang dikirim. Pesan dari Public API dan Proxy WABA tidak memicu
agent.message_out. Lihat Event & payload.