Perbandingan · Terbit

SDK resmi atau memanggil API langsung: apa yang benar-benar dibungkus paket PHP dan JavaScript Kasera Pay, apa yang tetap ditulis sendiri, dan kapan HTTP biasa justru lebih tepat

Jawaban singkatnya: untuk backend PHP 8.1+ atau JavaScript/TypeScript (Node 20.19+, Deno, Bun, atau edge runtime) yang membuat permintaan pembayaran dan menerima webhook, pakai SDK resmi, terutama karena verifikasi webhooknya. Panggil API HTTP langsung kalau bahasanya lain, kalau integrasinya memakai endpoint Langganan, atau kalau butuh field API yang lebih baru dari paket yang terpasang. Kedua jalur memanggil endpoint, kunci API, dan tarif yang sama. Yang berbeda hanya berapa banyak kode yang ditulis dan dirawat sendiri.

Perbandingan ini dibuat dari kode sumber kedua paket versi 0.1.0, bukan dari daftar fitur: paket npm kasera-pay dan paket Composer kasera/kasera-pay, keduanya tanpa dependency, dengan contoh pemakaian di halaman SDK resmi.

Yang dibungkus SDK, dan yang tidak

UrusanSDK 0.1.0HTTP langsung
Membuat, mengambil, dan mendaftar permintaan pembayarancreateTransaction, getTransaction, listTransactionsPOST dan GET /v1/transactions, ditulis sendiri
Metode yang aktif di akunlistPaymentMethodsGET /v1/payment_methods
Header Idempotency-KeyDikirim kalau key diberikan, tidak dibuat otomatisDitulis sendiri
ErrorException berisi status, kode, fields, dan request id. Gangguan jaringan menjadi status 0 dengan kode network_errorMembaca status dan body sendiri
Batas waktu30 detik per request (PHP: 10 detik untuk tersambung)Diatur sendiri
Verifikasi webhookSatu fungsi, lengkapDitulis sendiri, bagian yang paling sering salah
Retry dan backoffTidak adaTidak ada
Endpoint LanggananTidak adaSemua endpoint di spesifikasi
TypeTypeScript dibangkitkan dari spesifikasi API saat paket dirilisTidak ada, kecuali dibangkitkan sendiri

Alasan terkuat memakai SDK: verifikasi webhook

Membuat permintaan pembayaran dengan HTTP biasa hanya beberapa baris, dan kesalahannya langsung terlihat sebagai error. Verifikasi webhook sebaliknya: kode yang salah sering tetap berjalan di uji pertama, lalu gagal diam-diam atau menerima kiriman yang seharusnya ditolak. Fungsi Webhook::constructEvent di PHP dan constructWebhookEvent di JavaScript menangani empat hal yang paling sering terlewat saat header Kasera-Signature-V1 diverifikasi sendiri:

  1. HMAC-SHA256 dihitung atas t, titik, lalu body mentah persis seperti yang diterima. Framework yang sudah mengurai JSON lalu men-serialize ulang menghasilkan byte yang berbeda, dan tanda tangannya tidak pernah cocok.
  2. Selama 24 jam setelah signing secret dirotasi, header membawa dua entri v1, satu per secret. Kode yang hanya membaca entri pertama menolak kiriman yang sah di hari rotasi.
  3. Timestamp yang selisihnya lebih dari 300 detik dari jam server ditolak, supaya kiriman lama yang direkam tidak bisa diputar ulang.
  4. Perbandingan tanda tangan memakai fungsi waktu-konstan, bukan operator sama dengan.

Integrasi HTTP yang sudah lama berjalan tidak perlu dipindah seluruhnya. Mengganti fungsi verifikasinya dengan milik SDK sudah menutup keempat celah itu. Format header lengkapnya ada di dokumentasi webhook, dan urutan rotasi secret yang aman di artikel rotasi signing secret.

Yang tetap ditulis sendiri walau memakai SDK

SDK tidak mengulang request yang gagal. Satu request yang habis waktunya setelah 30 detik berakhir sebagai exception, padahal permintaan pembayarannya mungkin sudah dibuat di server. Satu-satunya pencegah tagihan ganda saat mengulang adalah header Idempotency-Key yang sama: key yang sama dengan body yang sama mengembalikan permintaan yang asli, dan key itu tidak pernah kedaluwarsa. Akibatnya, kalau permintaan dengan key itu sudah expired, failed, atau canceled, memanggil lagi dengan key yang sama hanya mengembalikan permintaan lama; percobaan pembayaran berikutnya untuk pesanan itu memakai key baru, misalnya orderId + '-2'. Tanpa key, setiap percobaan ulang menjadi permintaan pembayaran baru. external_id tidak mencegahnya.

Kode berikut mengulang hanya yang layak diulang (gangguan jaringan, 429, dan 5xx) dengan key yang sama, dan berhenti seketika pada 422, karena request yang salah tetap salah kalau dikirim ulang tanpa perubahan:

import { KaseraPay, KaseraPayError } from "kasera-pay";

const kasera = new KaseraPay(process.env.KASERA_API_KEY!);
const tunggu = (ms: number) => new Promise((r) => setTimeout(r, ms));

async function buatPembayaran(orderId: string, amount: number) {
  for (let percobaan = 1; ; percobaan++) {
    try {
      return await kasera.createTransaction(
        { amount, external_id: orderId, checkout: {} },
        { idempotencyKey: orderId },
      );
    } catch (e) {
      const layakDiulang =
        e instanceof KaseraPayError &&
        (e.status === 0 || e.status === 429 || e.status >= 500);
      if (!layakDiulang || percobaan === 4) throw e;
      await tunggu(2 ** percobaan * 1000);
    }
  }
}

Kode ini diuji dengan SDK 0.1.0 terhadap backend palsu: gangguan jaringan lalu 429 lalu 201 berakhir dengan satu permintaan pembayaran dan tiga request yang membawa key yang sama; 422 berhenti di percobaan pertama. Jeda 2, 4, lalu 8 detik dipilih karena batas 300 request per menit per kunci menjawab 429 rate_limited tanpa header Retry-After, jadi tidak ada yang bisa ditunggu selain jeda sendiri. Rinciannya ada di artikel rate limit dan lonjakan permintaan.

Dua hal lain juga tetap tugas integrasi: mencatat id setiap event webhook supaya kiriman ulang tidak diproses dua kali, dan memetakan status permintaan pembayaran, seperti pending, succeeded, dan expired, ke status pesanan sendiri.

Saat API lebih baru dari paketnya

Type TypeScript di SDK dibangkitkan dari spesifikasi API saat paket dirilis. Paket npm 0.1.0 dirilis 28 September 2026. Sesudahnya API menerima send_receipt pada create, field yang menyalakan atau mematikan email bukti pembayaran per pembayaran, dan field itu sudah ada di /v1/openapi.json. Di paket yang terpasang belum ada. Menulis send_receipt: true di object literal untuk createTransaction ditolak compiler dengan error TS2353 (diuji dengan TypeScript 5.9). Saat dijalankan, field itu tetap terkirim apa adanya, karena SDK meneruskan body dengan JSON.stringify.

Jalan keluarnya sempit dan disengaja: simpan body di variabel lalu beri type CreateTransactionRequest dengan as di satu tempat itu saja, dengan komentar yang menyebut field mana yang belum ada di paket. PHP tidak mengalami ini, karena SDK PHP menerima array biasa. Field yang ditambahkan ke API berikutnya akan bernasib sama selama paket yang terpasang belum memuatnya, termasuk field yang wajib untuk pembayaran di atas Rp 1.000.000 mulai 26 Oktober 2026 menurut referensi membuat transaksi.

Versi 0.1.0 juga berarti paketnya masih di bawah 1.0. Kunci versinya lewat lock file, dan baca catatan rilis sebelum menaikkan versi minor.

Kapan HTTP langsung yang tepat

Ringkasnya, per situasi

SituasiPilihan
Laravel, WordPress, atau PHP biasa, checkout dan webhookSDK PHP
Next.js, Express, Hono, atau Cloudflare WorkersSDK JavaScript
Integrasi HTTP lama yang sudah berjalanTetap HTTP, ganti verifikasi webhook dengan milik SDK kalau belum lengkap
Python, Go, Java, dan lainnyaHTTP langsung atau klien dari OpenAPI
Langganan lewat APISDK untuk pembayaran dan webhook, HTTP untuk Langganan
Butuh field yang lebih baru dari paketSDK dengan satu cast yang dikomentari, atau HTTP untuk panggilan itu

Apa pun pilihannya, uji dulu dengan kunci kp_test_: semua panggilan berjalan dari awal sampai akhir tanpa uang berpindah, dan pindah ke live cukup dengan mengganti kunci.

Pertanyaan yang sering muncul

Apakah memakai SDK mengubah tarif atau batas akun?

Tidak. SDK memanggil endpoint yang sama dengan kunci API yang sama, jadi tarif per metode, batas nominal, batas 300 request per menit per kunci, dan status pembayaran sama persis dengan panggilan HTTP biasa.

Bisakah SDK dipakai di browser atau aplikasi ponsel?

Jangan. Kedua SDK memegang kunci API rahasia, jadi tempatnya di server. Aplikasi ponsel dan halaman web meminta backend sendiri membuat permintaan pembayaran, lalu backend itulah yang memakai SDK atau HTTP biasa.

Ada SDK untuk Python, Go, atau Java?

SDK resmi saat ini hanya PHP dan JavaScript/TypeScript. Bahasa lain memanggil API HTTP langsung, atau membangkitkan klien dari spesifikasi OpenAPI di /v1/openapi.json.

Kalau sudah menulis integrasi HTTP sendiri, perlukah pindah ke SDK?

Tidak perlu kalau verifikasi webhooknya sudah benar: memakai body mentah, membandingkan semua entri v1, menolak timestamp yang lebih dari lima menit, dan membandingkan dengan fungsi waktu-konstan. Kalau salah satu belum, mengganti fungsi verifikasi itu saja dengan milik SDK sudah cukup, tanpa memindahkan panggilan lainnya.

Mulai sekarang

Terima pembayaran pertama minggu ini.

Daftar gratis, buat payment link atau pakai API, dan lihat statusnya berubah otomatis. Tanpa biaya bulanan, biaya transaksi hanya untuk pembayaran yang berhasil.

Dapatkan di Google PlayDownload di App Store