Memulai
Sumber daya inti
Lainnya

Hasil verifikasi melalui Webhook

SEEK Pass dapat mengirimkan status verifikasi melalui permintaan POST ke endpoint webhook mitra yang terdaftar. Mitra dapat mengelola webhook mereka dengan membuat dan memperbarui webhook, serta memutar secret webhook:
POST /api/partner/v2/webhooks
GET /api/partner/v2/webhooks
GET /api/partner/v2/webhooks/:id
PUT /api/partner/v2/webhooks
PUT /api/partner/v2/webhooks/:id/secret
DELETE /api/partner/v2/webhooks/:id

Mendaftarkan webhook

Contoh permintaan resource webhook:
# POST /api/partner/v2/webhooks

{
  "name": "SEEK Pass Webhook",          // Optional
  "description": "SEEK Pass Webhook",   // Optional
  "url": "https://example.com/webhook"  // Required
}
Contoh respons resource webhook:
{
  "id": "03a7c560-93cd-4579-a26a-a3b98efa8a49",
  "name": "SEEK Pass Webhook",
  "description": "SEEK Pass Webhook",
  "url": "https://example.com/webhook",
  "secret": "23a8db7b1b368dd0e30eff95b048b994e892000e69a4fbb3ca78ff92e13ad1f7"
}
Lihat dokumentasi Open API untuk detail lebih lanjut tentang memperbarui endpoint webhook Anda, serta format permintaan dan respons.

Peristiwa webhook

SEEK Pass dapat memberikan pembaruan untuk berbagai peristiwa pada tahap berbeda dalam alur kerja verifikasi. Saat ini kami mendukung peristiwa status verifikasi berikut yang dikirim ke webhook yang terdaftar:
  • canceled
  • verified
Caution
Peristiwa webhook hanya menyertakan beberapa informasi ringkas tingkat tinggi seperti status. Mitra harus memanggil API status verifikasi dengan ID permintaan untuk mengambil hasil verifikasi lengkap seperti nama lengkap dan tanggal lahir.
Contoh event webhook:
{
  "event_id": "5c4ac58b-5cf9-40a0-b60a-28c0137663ed",
  "request_id": "7cbc7e51-82f5-43ec-8d63-b7cdf1170425",
  "type": "vwsp_request.verified",
  "created_at": "2025-04-15T02:14:01.307391Z"
}

Memverifikasi tanda tangan webhook (HMAC-SHA256)

Setiap webhook dikaitkan dengan secret yang dibuat otomatis sebagai kunci bersama antara mitra dan SEEK Pass untuk komunikasi yang aman. SEEK Pass menggunakan secret ini untuk menandatangani setiap payload peristiwa keluar menggunakan HMAC-SHA256. Anda harus memvalidasi tanda ini pada setiap permintaan masuk untuk memastikan bahwa itu benar-benar berasal dari SEEK Pass dan tidak diubah.SEEK Pass menyertakan dua header pada setiap pengiriman webhook:
HeaderDeskripsi
X-SignatureHex digest HMAC-SHA256 dari pesan yang ditandatangani
X-TimestampTimestamp Unix saat peristiwa dikirim
HMAC dihitung atas pesan yang menggabungkan timestamp dan isi permintaan mentah, biasanya digabungkan sebagai <timestamp>.<raw_body>. Menyertakan timestamp adalah pilihan desain yang disengaja untuk melindungi dari serangan replay, ketika permintaan yang valid ditangkap dan dikirim ulang secara berbahaya di lain waktu.Untuk memvalidasi webhook masuk, endpoint Anda sebaiknya:
  • 1. Ekstrak nilai X-Signature dan X-Timestamp dari header permintaan.
  • 2. Bangun ulang pesan yang ditandatangani dengan menggabungkan timestamp dan isi mentah sebagai <timestamp>.<raw_body>.
  • 3. Hitung ulang HMAC-SHA256 dari pesan tersebut menggunakan secret webhook Anda sebagai kunci.
  • 4. Bandingkan HMAC yang Anda hitung dengan header X-Signature menggunakan perbandingan waktu konstan untuk mencegah serangan timing.
  • 5. Periksa timestamp untuk menolak permintaan yang lebih lama dari jendela toleransi yang wajar (mis. ±15 menit) guna mengurangi serangan replay.
Caution
Selalu gunakan isi permintaan mentah yang belum di-parse saat menghitung HMAC. Mengurai JSON lalu mem-serialisasi ulang dapat mengubah urutan byte dan menyebabkan validasi tanda gagal.
Contoh Ruby untuk verifikasi HMAC yang aman
require "openssl"
require "active_support/security_utils"

TOLERANCE_SECONDS = 900

def verify_webhook(raw_body, secret, given_hmac, timestamp, tolerance_seconds = TOLERANCE_SECONDS)
  # Step 1: Reject stale requests to prevent replay attacks
  age = Time.now.to_i - timestamp.to_i
  return false if age.abs > tolerance_seconds

  # Step 2: Reconstruct the signed message
  signed_message = "#{timestamp}.#{raw_body}"

  # Step 3: Recompute the HMAC-SHA256
  calculated_hmac = OpenSSL::HMAC.hexdigest("SHA256", secret, signed_message)

  # Step 4: Constant-time comparison to prevent timing attacks
  return false unless calculated_hmac.bytesize == given_hmac.bytesize
  ActiveSupport::SecurityUtils.secure_compare(calculated_hmac, given_hmac)
end

def handle_event(raw_body, secret, given_hmac, timestamp)
  return if !verify_webhook(raw_body, secret, given_hmac, timestamp)

  event = JSON.parse(raw_body)

  # Step 5: Idempotency check — discard duplicate events within the tolerance window
  return if event_already_processed?(event["event_id"])
  mark_event_as_processed(event["event_id"])

  # ... handle event
end
Contoh Node.js untuk verifikasi HMAC yang aman
const crypto = require("crypto");

const TOLERANCE_SECONDS = 900;

function verifyWebhook(rawBody, secret, givenHmac, timestamp, toleranceSeconds = TOLERANCE_SECONDS) {
  // Step 1: Reject stale requests to prevent replay attacks
  const age = Math.abs(Math.floor(Date.now() / 1000) - parseInt(timestamp, 10));
  if (age > toleranceSeconds) return false;

  // Step 2: Reconstruct the signed message
  const signedMessage = `${timestamp}.${rawBody}`;

  // Step 3: Recompute the HMAC-SHA256
  const calculatedHmac = crypto
    .createHmac("sha256", secret)
    .update(signedMessage, "utf8")
    .digest(); // Returns a Buffer

  const givenHmacBuffer = Buffer.from(givenHmac, "hex");

  // Step 4: Constant-time comparison to prevent timing attacks
  if (calculatedHmac.length !== givenHmacBuffer.length) return false;
  return crypto.timingSafeEqual(calculatedHmac, givenHmacBuffer);
}

async function handleEvent(rawBody, secret, givenHmac, timestamp) {
  if (!verifyWebhook(rawBody, secret, givenHmac, timestamp)) return;

  const event = JSON.parse(rawBody);

  // Step 5: Idempotency check — discard duplicate events within the tolerance window
  if (await isEventAlreadyProcessed(event.event_id)) return;
  await markEventAsProcessed(event.event_id);

  // ... handle event
}

Mengganti secret webhook

Mitra dapat mengganti secret webhook menggunakan endpoint ini: PUT /api/partner/v2/webhooks//secret.Selama periode transisi, peristiwa webhook dapat ditandatangani dengan secret sebelumnya. Endpoint webhook mitra harus dapat memverifikasi peristiwa yang ditandatangani dengan secret lama dan baru. Pendekatan yang aman adalah mencoba secret baru terlebih dahulu, lalu beralih ke yang lama.Contoh respons untuk rotasi secret:
{
  "id": "03a7c560-93cd-4579-a26a-a3b98efa8a49",
  "name": "SEEK Pass Webhook",
  "description": "SEEK Pass Webhook",
  "url": "https://example.com/webhook",
  "secret": "NEW_SECRET"
}

Catatan

Caution
Peristiwa webhook dapat dikirim tidak berurutan karena faktor seperti latensi jaringan. Untuk membantu Anda menentukan urutan yang benar, payload setiap peristiwa mencakup stempel waktu created_at. Kami menyarankan untuk menerapkan pemrosesan peristiwa idempoten karena peristiwa duplikat dapat terjadi. Setiap peristiwa mencakup event_id yang dapat digunakan untuk mengidentifikasi dan melewati peristiwa yang berulang.
Info
Jika endpoint webhook Anda tidak merespons dengan sukses (HTTP 200) dalam 5 detik, SEEK Pass akan mencoba mengirim ulang peristiwa tersebut hingga 5 kali lagi.
Info
SEEK Pass mengirim peristiwa verifikasi dari alamat IP yang ditetapkan yang dipublikasikan di sini, sehingga mitra dapat memasukkan IP ini ke allowlist untuk konektivitas yang aman.

Alamat IP SEEK Pass

Alamat IP berikut digunakan oleh SEEK Pass untuk mengirim peristiwa webhook. Mitra sebaiknya memasukkan IP ini ke allowlist agar pengiriman notifikasi webhook andal.
Caution
Tindakan diperlukan: Rentang IP baru (18.98.198.160/28) akan ditambahkan dalam waktu dekat. Pastikan rentang ini ditambahkan ke daftar yang diizinkan Anda lebih awal untuk menghindari gangguan pada pengiriman webhook.
LingkunganAlamat IP
Staging
  • 13.210.155.65
  • 52.64.188.102
  • 54.79.229.97
  • 18.98.198.160/28
Produksi
  • 13.210.238.239
  • 52.63.199.197
  • 54.252.19.190
  • 18.98.198.160/28