Lewati ke konten

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

HTTP
POST /csku/webhook HTTP/1.1
Host: api.toko-anda.com
Content-Type: application/json
Authorization: 3f9a1c7e5b2d4f6a8c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d9f2a4c6e8b0d1f3a

{"event":"channel.message_in","timestamp":1792041600, ...}
  • Authorization berisi Secret Key Anda apa adanya: tanpa awalan Bearer, 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.

JavaScript
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
<?php
$ok = hash_equals(getenv('CSKU_SECRET'), $_SERVER['HTTP_AUTHORIZATION'] ?? '');
Python
import hmac
ok = hmac.compare_digest(request.headers.get("Authorization", ""), SECRET)
Go
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:

  1. Siapkan server agar sementara menerima secret lama atau baru.
  2. Reset secret di dashboard, lalu simpan secret baru di server.
  3. Hapus secret lama dari server.

Aturan sukses

CSKU menganggap pengiriman sukses hanya jika body respons Anda berupa JSON dengan field success bernilai benar:

JSON
{ "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 success tidak ada.
  • success bernilai false.

Jadwal retry

Pengiriman yang gagal dicoba ulang otomatis. Total maksimal 4 percobaan:

PercobaanWaktu (perkiraan)
1Saat event terjadi
2Langsung setelah percobaan 1 gagal
3Sekitar 30 detik setelah percobaan 2
4Sekitar 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. Simpan message.id yang sudah diproses dan abaikan duplikat. Jangan pakai timestamp, 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:

  1. Verifikasi Authorization.
  2. Simpan payload ke antrean atau database.
  3. Balas {"success": true}.
  4. 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 (bukan localhost atau IP privat).
  • Sertifikat TLS server valid dan tidak kedaluwarsa.
  • Firewall atau WAF (misalnya proteksi bot) tidak memblokir request POST dari server CSKU.
  • Server membaca header Authorization dengan 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.