SEEK Pass can deliver verification status through POST requests to partner-registered webhook endpoints. Partners can manage their webhooks by creating and updating them, as well as rotating webhook secrets.
SEEK Pass can provide updates for various events at different stages of a verification workflow. Sample events are listed below:
incompletecanceledverifiedEach webhook is associated with an automatically generated secret that serves as a shared key between partners and SEEK Pass to ensure secure communication. Our service uses this secret to generate an HMAC-SHA256 signature of the event payload, which is transmitted in the request header (e.g., X-Signature). To mitigate replay attacks, a timestamp is also included in the headers (e.g., X-Timestamp) and incorporated into the HMAC calculation.
Partners can use the shared secret to validate message signatures from SEEK Pass. When receiving a message, partners should verify its authenticity by recalculating the HMAC and comparing it against the header signature. To prevent timing attacks, implement a constant-time comparison method:
require "openssl" require "active_support/security_utils" def secure_hmac_compare(data, key, given_hmac) calculated_hmac = OpenSSL::HMAC.hexdigest("SHA256", key, data) # secure_compare requires equal-length strings return false unless calculated_hmac.bytesize == given_hmac.bytesize # Constant-time comparison ActiveSupport::SecurityUtils.secure_compare(calculated_hmac, given_hmac) end
const crypto = require("crypto"); function generateHmac(key, data) { return crypto.createHmac("sha256", key).update(data, "utf8").digest(); // return Buffer } function safeCompare(a, b) { // Both must be Buffers and same length if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) return false; if (a.length !== b.length) return false; // Constant-time comparison return crypto.timingSafeEqual(a, b); }
Sample webhook resource request:
# POST /api/partner/v2/webhooks { "name": "SEEK Pass Webhook", // Optional "description": "SEEK Pass Webhook", // Optional "url": "https://example.com/webhook" }
Sample webhook resource response:
{ "id": "03a7c560-93cd-4579-a26a-a3b98efa8a49" "name": "SEEK Pass Webhook", "description": "SEEK Pass Webhook", "url": "https://example.com/webhook", "secret": "23a8db7b1b368dd0e30eff95b048b994e892000e69a4fbb3ca78ff92e13ad1f7" }
The webhook event only includes the verification status, so partners should call the verification status API with the request ID to get complete verification result such as fullname, date of birth, and other details.
Sample webhook event:
{ "event_id": "5c4ac58b-5cf9-40a0-b60a-28c0137663ed", "request_id": "7cbc7e51-82f5-43ec-8d63-b7cdf1170425", "type": "verification", "status": "verified", "created_at": "2025-04-15T02:14:01.307391Z" }
Webhook events may be delivered out of order due to factors like network latency. To help you determine the correct sequence, each event payload includes a created_at timestamp. We recommend implementing idempotent event processing since duplicate events may occur. Each event includes an event_id that can be used to identify and skip repeated events.
If your webhook endpoint does not respond successfully (HTTP 200) within 5 seconds, SEEK Pass will retry sending the event up to 5 more times.
SEEK Pass sends verification events from designated IP addresses that we will announce, allowing partners to whitelist these IPs for secure connectivity.