Skip to main content

webhooks-guide

Webhooks Integration Guide

Overview

eFICA supports outgoing webhooks so external systems can receive notifications when key events occur.

Design goals:

  • At-least-once delivery (retries on transient failures)
  • Receiver-side idempotency via a stable eventId (duplicates are possible)
  • Full audit trail of deliveries and attempts

Webhook configuration (public API)

Webhook subscriptions are managed via the public API (admin-only):

Each subscription is scoped to the authenticated partner and contains:

  • url: destination webhook endpoint (HTTPS recommended; required in production environments)
  • eventTypes: which event types to receive
  • enabled: toggle deliveries on/off
  • secret: shared signing secret (stored encrypted at rest; only returned on creation)

Receiver endpoint expectations

All webhook deliveries are sent as:

  • Method: POST
  • Content-Type: application/json
  • Body: a JSON object (see event payloads below)

Headers and signature (HMAC SHA-256)

Required headers:

  • Content-Type: application/json
  • X-Efica-Signature: t=<unixSeconds>,v1=<hexHmac>

Additional headers:

  • X-Efica-Event-Id: <eventId>
  • X-Efica-Event-Type: <eventType>
  • User-Agent: efica-webhooks/2.0

Signature computation:

  1. Use the exact JSON string sent as the request body (no pretty-print / extra whitespace).
  2. Compute:
    • signedPayload = "<unixSeconds>.<rawBody>"
    • v1 = HMAC_SHA256_HEX(secret, signedPayload)
  3. Send: X-Efica-Signature: t=<unixSeconds>,v1=<hexHmac>

Receiver verification recommendations:

  • Reject if timestamp skew is too large (e.g. > 5 minutes) to mitigate replay.
  • Compare HMAC in constant time.
  • Store and dedupe on eventId (at-least-once delivery can produce duplicates).

Event types

1) customer_portal.application_status_changed

Emitted when a Customer Portal onboarding application changes status (e.g. created, emailed, opened, completed, expired).

Example payload (schemaVersion 1):

{
"schemaVersion": 1,
"eventId": "d46b29c4-0e39-4a86-8b4b-7f1a0e9b8d2c",
"eventType": "customer_portal.application_status_changed",
"occurredAt": "2026-01-25T12:00:00.000Z",
"sourceEntity": "onboarding",
"sourceId": "123",
"externalID": "889912d3-xxxx-xxxx-xxx-b77bb61231c1",
"onboardingId": "123",
"status": "Client Pending",
"previousStatus": "Email Sent",
"eficaIndividualGuid": null,
"data": {
"reason": "optional",
"expiresAt": "2026-02-01T12:00:00.000Z"
}
}

2) individual.updated

Emitted when the eFICA Individual record changes in a way that may cause drift in external systems.

Routing requirement:

  • externalID and onboardingId are always included so external systems can route updates correctly even when a person has multiple applications.

Example payload (schemaVersion 1):

{
"schemaVersion": 1,
"eventId": "7c44c2c1-2a0f-4c6f-bc47-3f8a9e5a1f2b",
"eventType": "individual.updated",
"occurredAt": "2026-01-25T12:05:00.000Z",
"sourceEntity": "ficaIndividual",
"sourceId": "123e4567-e89b-12d3-a456-426614174000",
"externalID": "889912d3-xxxx-xxxx-xxx-b77bb61231c1",
"onboardingId": "123",
"eficaIndividualGuid": "123e4567-e89b-12d3-a456-426614174000",
"data": {
"ficaStatus": "Approved",
"riskDescription": "High Risk",
"amlScreeningResults": { "any": "json" },
"clientValidationResults": { "any": "json" },
"changedFields": [
"riskDescription",
"memberCheckResults",
"kycResult"
]
}
}

Response codes and retries

  • Success: Any 2xx response marks the delivery as successful.
  • Retryable failures: Network errors/timeouts, and HTTP 408, 429, 500–599.
  • Non-retryable failures: HTTP 400–499 excluding 408/429 (treated as permanent until configuration is fixed).

Retry schedule (example):

  • attempt 1: immediate
  • attempt 2: +1 minute
  • attempt 3: +5 minutes
  • attempt 4: +15 minutes
  • attempt 5: +60 minutes
  • attempt 6: +6 hours
  • attempt 7: +24 hours
  • then: mark failed-final and stop retrying