Menjawab kebutuhan webhook Laravel terpercaya

Untuk memastikan integrasi publik tetap dapat diandalkan, kontrak API webhook harus menetapkan struktur payload, respons sukses maupun error, serta aturan autentikasi. Dengan dasar tersebut, klien tahu apa yang diharapkan dan server bisa memberi tanggapan yang konsisten meskipun terjadi retry atau gangguan jaringan.

Artikel ini membahas cara merancang kontrak API Laravel yang mencakup payload terdefinisi, mekanisme autentikasi Bearer/Signature, strategi idempotensi, penanganan retry (termasuk header Retry-After dan deduplikasi), serta observasi melalui middleware, FormRequest, rate limit, dan job queue.

Menetapkan kontrak payload dan respons

Kontrak dimulai dari payload: sebutkan field wajib, tipe data, dan batas panjang. Gunakan FormRequest Laravel agar validasi dijalankan sebelum controller dipanggil. Contoh:

class WebhookPayloadRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'event' => 'required|string|max:64',
            'data.id' => 'required|string',
            'data.attributes' => 'required|array',
            'metadata.timestamp' => 'required|date_format:Y-m-d\TH:i:sP',
        ];
    }

    public function authorize(): bool
    {
        return true;
    }
}

Jika validasi gagal, FormRequest otomatis mengembalikan respons 422. Kontrak harus menyertakan format respons sukses (misalnya {"status":"OK"}) dan format error dengan kode dan pesan. Gunakan standar seperti:

  • 200 / 202 ketika payload diterima dan diproses.
  • 4xx untuk permintaan tidak valid (validasi, autentikasi, rate limit).
  • 5xx jika sistem internal gagal; sertakan ID request agar klien bisa melaporkan.

Dokumentasikan header yang diperlukan (Content-Type, Trace-ID, dll.) agar klien tahu data apa yang harus dikirim.

Autentikasi dan validasi yang konsisten

Gunakan dua lapis autentikasi untuk memastikan webhook tidak disalahgunakan. Lapisan pertama bisa Bearer token statis atau rotatable; lapisan kedua Signature HMAC untuk integritas payload.

Buat middleware custom yang membaca header Authorization: Bearer ... dan menghitung HMAC payload:

class VerifyWebhookSignature
{
    public function handle(Request $request, Closure $next)
    {
        $secret = config('services.webhook.secret');
        $signature = hash_hmac('sha256', $request->getContent(), $secret);
        if (!hash_equals($signature, $request->header('X-Signature', ''))) {
            return response()->json(['error' => 'Invalid signature'], 401);
        }
        return $next($request);
    }
}

Middleware ini bisa dijalankan setelah middleware rate limit untuk menolak permintaan berlebih. Pastikan middleware ditambahkan ke route grup webhook dan dilindungi oleh rate limiter (Laravel Throttle) agar tidak kebanjiran traffic dari klien sama.

Idempotensi dan retry yang bisa diprediksi

Webhook publik biasanya di-retry oleh pihak pengirim jika tidak menerima respons sukses. Untuk mencegah duplikasi, kontrak harus mencakup header Idempotency-Key yang unik per event.

Implementasi:

  1. Simpan entri di tabel webhook_events berisi idempotency_key dan status proses.
  2. Gunakan firstOrCreate agar duplikat tidak memicu pekerjaan baru.
  3. Tambahkan logika deduplikasi di job queue, misalnya jangan proses ulang jika status sudah completed.

Untuk retry, kirim header Retry-After ketika sistem overload atau maintenance. Contoh:

return response()->json(['error' => 'service unavailable'], 503)
    ->header('Retry-After', 60);

Jika Laravel mendeteksi data belum diproses, kirim status 202 dan jalankan job asinkron. Pastikan job queue (Redis/Database) idempoten dan gunakan unique job agar tidak terjadi eksekusi paralel.

Pipeline observasi dan ketahanan operasional

Observasi penting untuk mendeteksi edge case integrasi. Terapkan:

  • Logging: simpan payload minimal ID/event, status, dan respons. Gunakan channel khusus agar log webhook mudah dicari.
  • Monitoring: buat metric jumlah webhook sukses/gagal per klien untuk mendeteksi anomali.
  • Job Queue: gunakan job untuk memproses payload berat; job harus menangani kegagalan dengan tries dan backoff.

Untuk keamanan, manfaatkan middleware seperti:

  • ThrottleRequests: atur limit per IP/API key agar tidak melewati kapasitas.
  • ValidateSignature: seperti di atas untuk menolak payload palsu.
  • EnsureHttps: pastikan webhook hanya menerima via HTTPS.

FormRequest mengurangi duplikat validasi di controller. Untuk mengamankan data, enkripsi payload sensitif saat disimpan atau simpan hanya referensi (misalnya ID) lalu tarik data saat dibutuhkan.

Contoh JSON dan checklist validasi

Berikut contoh payload webhook menurut kontrak:

{
  "event": "invoice.paid",
  "data": {
    "id": "inv_12345",
    "attributes": {
      "amount": 250000,
      "currency": "IDR"
    }
  },
  "metadata": {
    "timestamp": "2024-10-05T08:35:00+07:00",
    "source": "billing-service"
  }
}

Checklist validasi yang harus dilakukan sebelum memproses webhook:

  • Validasi payload melalui FormRequest (rule, tipe, maksimal panjang).
  • Verifikasi header Authorization dan signature HMAC dengan middleware.
  • Periksa Idempotency-Key dan hindari pemrosesan ulang jika sudah selesai.
  • Catat log request/response untuk debugging.
  • Kiriman status 503 dengan Retry-After jika sistem tidak siap.
  • Gunakan job queue terkontrol dengan tries, backoff, dan deduplikasi job.

Dengan kontrak terdefinisi, tim Laravel bisa menjamin webhook publik lebih mudah diintegrasikan dan lebih tahan terhadap retry serta kesalahan operasional.