Straightforward integration through API and webhooks
The recommended flow: your backend creates a verification through the API, the applicant completes capture through Wathiq, and your backend receives a signed webhook with the result.
What the applicant sees is UX only — never treat it as proof of a result. The authoritative result arrives via a signed webhook and is then fetched from the API.
Authentication
Send your API key as a Bearer token or an X-API-Key header. The secret is displayed only once at creation — keep it in a server-side secret manager, never in browser or mobile code.
Authorization: Bearer wk_live_<key-prefix>_<secret>
# or
X-API-Key: wk_live_<key-prefix>_<secret>Create a verification
Create a request through the API and receive a verification ID and a hosted verification URL to send to the applicant.
{
"verification_type": "national_id",
"external_reference": "customer-829174",
"expires_in_minutes": 1440
}{
"id": "c767ef96-2209-4fd6-9062-97e2687886e5",
"status": "session_created",
"decision": null,
"verification_url": "https://<verify-domain>/verify#session_token=...",
"expires_at": "2026-08-02T12:00:00Z"
}Supported types: national ID, old (non-electronic) passport, ePassport, and generic types by agreement with Wathiq.
Retrieve the result
After receiving the decision webhook, fetch the authoritative result. The decision is accepted, review, or rejected — treat review as pending, not as a rejection.
{
"status": "decided",
"decision": "accepted",
"assurance_level": "registry_matched",
"risk_score": 0.08,
"completed_at": "2026-08-01T12:08:31Z"
}Webhooks
Wathiq sends HTTPS POST requests signed with HMAC-SHA256. Always verify the signature against the raw body before JSON parsing, check the timestamp, and deduplicate event IDs.
X-Wathiq-Event: verification.decided
X-Wathiq-Event-Id: <event-uuid>
X-Wathiq-Timestamp: <unix-seconds>
X-Wathiq-Signature: v1=<hex-hmac-sha256>signed_payload = event_id + "." + timestamp + "." + raw_body
expected = "v1=" + hex(HMAC-SHA256(signing_secret, signed_payload))
# use constant-time comparisonRetries: up to 3 attempts per event, with roughly 30- then 60-second delays after the first two failures. Delivery is at-least-once — deduplicate using a unique constraint on the event ID.
This is a working summary, not the full documentation. Request access for the complete integration guide and OpenAPI specification.