Skip to content
Developer guide

Register and verify webhooks

Browse developer guides

Use webhooks to receive events at your HTTPS receiver. Obtain the authorized partner or customer ID for your account and complete API authentication.

1. Register a receiver

Call POST /api/Webhook/register?partnerId=<partnerId> with the body below. For a customer subscription, use customerId instead. Always supply exactly one valid target ID; the id property in a subscription response is a separate subscription identifier.

{
  "webhookUri": "https://receiver.example.com/webhooks/plexe",
  "isActive": true,
  "webhooks": [
    "WB_Customer_Created",
    "WB_Application_Created"
  ]
}

Choose events explicitly. An omitted or empty webhooks list subscribes to all supported events. Initial registration assigns the subscription ID and secret on the server. Re-registering updates the URI and event list; do not use it to rotate the secret or assume it updates every subscription property.

2. Read back the saved configuration

Call GET /api/Webhook/get-subscription?partnerId=<partnerId> to check the saved URI, event list and server-issued secret. Treat the secret as sensitive server-side configuration. Confirm that a subscription was returned; an HTTP success alone does not prove registration was saved.

Get-registered-webhooks returns event names only. Get-all-subscriptions is restricted to webhook administrators and is not a normal partner setup step.

To change a URI, call update-webhook-uri with webhookUri and the target ID in the query. Register first: updating a missing subscription does not create it. Unregister requires a subscription JSON body and the same target query parameter, and removes the subscription.

3. Verify the signature before processing

Deliveries include the header abp-webhook-signature. Compute HMAC-SHA256 over the exact UTF-8 request body bytes using the saved secret as the UTF-8 key. The header format is sha256= followed by uppercase hexadecimal bytes separated with hyphens. Compare the expected and supplied values using a constant-time comparison.

Do not parse and reserialize the body before verification; whitespace and property-order changes alter the signature. Reject missing or invalid signatures before trusting event contents. The public API's handler and test receiver are not a substitute for verification in your receiver.

4. Read the event envelope

{
  "id": "11111111-1111-4111-8111-111111111111",
  "webhookEvent": "WB_Application_Created",
  "data": {},
  "creationTimeUtc": "2026-09-01T00:00:00Z"
}

This illustrates the envelope only. data is a JSON value containing event-specific fields, not a JSON-encoded string. Application-created data may include extraInformation.years as a string. Ignore additional fields that your integration does not need.

Do not use the envelope id alone as a universal deduplication key: current publishers can reuse a target identifier across events. Use an event-specific event ID where supplied and business identifiers/state to make processing idempotent. No delivery ordering or fixed retry schedule is promised by this guide.

5. Test delivery

Call POST /api/Webhook/generate-simulated-webhook?eventName=WB_Application_Created&partnerId=<partnerId> after registration. The selected event must be in the subscription. This sends to the saved receiver, so use a test receiver. Unsupported names are rejected.

Check receipt, signature verification and your response in the receiver. A successful simulation request alone does not prove delivery succeeded. Once the event has been accepted safely, return a successful HTTP response promptly.

Endpoint reference

Event catalogue

These are the current subscription event names. Simulation supports a subset; a registered event can still be rejected by the simulation endpoint.

EventPurpose
WB_Partner_RequestPartner request notifications
WB_Application_CreatedApplication created
WB_Customer_CreatedCustomer created
WB_Customer_And_Application_CreatedCustomer and application created
WB_Application_Current_ProcessCurrent process updates
WB_Application_Status_ChangedApplication status changes
WB_Loan_CreatedLoan created
WB_Bank_Transactions_RefreshBank transaction refresh
WB_Communication_SentCommunication sent
WB_Loan_Withdrawal_CompletedLoan withdrawal completed
WB_Send_Secondary_Applicant_NoticeSecondary applicant notices
WB_Under_ReviewUnder review notifications
WB_Send_SmsSMS send event
WB_Send_OtpOTP send event
WB_Send_Loan_OtpLoan OTP send event
WB_Application_CancelledApplication cancelled
WB_Send_Two_Factor_CodeTwo-factor code sent
WB_Send_Application_ReadyApplication ready notification
WB_Application_ReadyApplication ready
WB_Loan_Enabled_Or_DisabledLoan enabled or disabled
WB_Loan_ClosedLoan closed
WB_Loan_OpenedLoan opened
MethodRouteInputsSwagger success
POST/api/Webhook/registerquery: partnerId; query: customerId; body: body — WebhookSubscription (required)200: Not specified
POST/api/Webhook/unregisterquery: partnerId; query: customerId; body: body — WebhookSubscription (required)200: Not specified
POST/api/Webhook/update-allquery: partnerId; query: customerId200: Not specified
POST/api/Webhook/handlerbody: body — WebhookPayload (required)200: Not specified
POST/api/Webhook/generate-simulated-webhookquery: eventName; query: partnerId; query: customerId200: Not specified
GET/api/Webhook/get-registered-webhooksquery: partnerId; query: customerId200: Not specified
GET/api/Webhook/get-subscriptionquery: partnerId; query: customerId200: WebhookSubscription
GET/api/Webhook/get-all-subscriptionsNone200: WebhookSubscriptionSummary[]
POST/api/Webhook/update-webhook-uriquery: webhookUri (required); query: partnerId; query: customerId200: Not specified