Webhook Setup
Purpose: Subscribe an integrator-controlled HTTPS endpoint to Reap's Compliance notification system, manage the webhook subscription lifecycle, and securely consume signed event payloads for the supported KYC verification flows.
The Notifications API is available only for the KYCaaS and Universal KYC verification methods. Webhook notifications are triggered exclusively for these two verification flows.
When to Use This
Use this guide when you need to:
- Receive asynchronous KYC decision updates for cardholders onboarded via KYCaaS or Universal KYC
- Register an HTTPS endpoint with Reap's Compliance API to consume the
account_status_changeevent - Manage existing webhook subscriptions by listing, retrieving, updating, or deleting them
- Verify the authenticity of incoming webhook payloads using Reap's RSA public key
- Validate the integration in the sandbox environment before enabling webhook delivery in production
Overview
The Webhook Setup workflow registers an integrator-controlled HTTPS endpoint with Reap's Compliance API so that asynchronous events generated by the supported KYC flows can be delivered to the integrator's backend. Subscriptions are managed through the /notification resource, which supports the full lifecycle of a webhook configuration: registration, retrieval, update, and deletion.
Every webhook delivery is signed with Reap's RSA private key, allowing the integrator to verify the authenticity and integrity of the payload using the environment-specific RSA public key. Subscriptions are scoped to the business associated with the API key and apply to events generated for entities owned by that business.
The notification channel returns event payloads to a single subscribed URL per configuration, with the channel, subscribed event types, and webhook URL all returned in the registration response. Delivery is retried with exponential backoff when the integrator's endpoint fails to respond within the configured timeout.
Prerequisites
- An active Reap Compliance integration using either KYCaaS or Universal KYC for the program
- A sandbox API key generated from the Reap Card Issuance Dashboard and, once provisioned, a production API key linked to the integrator's business
- A publicly reachable HTTPS webhook endpoint capable of returning a
200 OKresponse within 5 seconds - Reap's RSA public key for the relevant environment configured on the integrator side for webhook signature verification
- The ability to verify RSA-SHA512 signatures using the raw JSON payload received in the request body
All Notifications API requests must be authenticated using the API key issued for the relevant environment. The business derived from the API key scopes every webhook configuration to the integrator's business.
Key Concepts
Notification Subscription
- Webhook configuration registered against the Reap Compliance API at the
/notificationendpoint - Persisted under a unique
notificationIdreturned at creation time and used in all subsequent management calls - Scoped to the business associated with the API key used at registration
Notification Channel
- Delivery channel configured for the subscription
- Webhook delivery is identified by
notificationChannel: "WEBHOOK"
Notification Event Types
- List of event types the subscription is registered for
- Submitted as
notificationTypesand currently supportsaccount_status_changefor account status updates including feature access changes
Webhook URL
- HTTPS endpoint where Reap delivers signed event payloads via
POST - Must be reachable from the public internet and able to respond with
200 OKwithin 5 seconds
Signature Verification
- Every webhook request is signed by Reap using RSA-SHA512 and the signature is delivered in the
reap-signaturerequest header - The integrator verifies the signature against the raw JSON payload using the environment-specific RSA public key
- Distinct public keys are issued for the sandbox and production environments
Webhook Configuration Limit
- Each business may register up to 10 webhook configurations across all subscriptions
Flow Overview
- Generate sandbox and production API keys via the Reap Card Issuance Dashboard
- Provision a publicly reachable HTTPS endpoint configured to verify Reap's RSA-SHA512 signature
- Register the webhook endpoint via
POST /notificationand subscribe to theaccount_status_changeevent type - Retrieve, update, or delete the webhook configuration via the
/notification/notificationIdendpoints as required - Receive signed event payloads on the registered endpoint and verify each request using the environment-specific public key
- Validate the integration end to end in the sandbox environment before enabling the webhook configuration in production
API Summary
| Action | Endpoint | Method | Use Case |
|---|---|---|---|
| Register webhook subscription | /notification | POST | Register a webhook URL and subscribe to one or more notification event types |
| List webhook subscriptions | /notification | GET | Retrieve all webhook configurations registered for the business |
| Get a webhook subscription | /notification/notificationId | GET | Retrieve a single webhook configuration by notificationId |
| Update a webhook subscription | /notification/notificationId | PUT | Update the webhook URL, channel, or subscribed event types of an existing configuration |
| Delete a webhook subscription | /notification/notificationId | DELETE | Remove an existing webhook configuration |
Environment Endpoints
The Notifications API is environment-scoped and authenticated using the API key issued for that environment.
| Environment | Base URL | Authentication Header |
|---|---|---|
| Sandbox | https://sandbox-compliance.api.reap.global | x-reap-api-key: <sandbox-api-key> |
| Production | https://compliance.api.reap.global | x-reap-api-key: <production-api-key> |
Use the sandbox API key and base URL throughout the integration and switch to the production API key and base URL only after the webhook integration has been validated end to end.
Webhook Setup
Step 1: Register a Webhook Subscription
Register an HTTPS endpoint with Reap's Compliance API to begin receiving asynchronous event notifications for the subscribed event types.
Call the Register Webhook Endpoint
Use POST /notification to register the webhook URL and subscribe it to one or more notification event types.
Sample Request (cURL)
curl --request POST \
--url https://sandbox-compliance.api.reap.global/notification \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'x-reap-api-key: ********' \
--data '{
"webhookUrl": "https://your-domain.com/webhooks/reap",
"notificationChannel": "WEBHOOK",
"notificationTypes": ["account_status_change"]
}'Sample Request (JavaScript / Node.js)
const url = 'https://sandbox-compliance.api.reap.global/notification';
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
'x-reap-api-key': '********',
},
body: JSON.stringify({
webhookUrl: 'https://your-domain.com/webhooks/reap',
notificationChannel: 'WEBHOOK',
notificationTypes: ['account_status_change'],
}),
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));Key Input
| Parameter Name | Type | Description |
|---|---|---|
notificationTypes | array of string | List of notification event types to subscribe to (e.g. account_status_change) |
Sample Response
{
"id": "notification-id-123",
"channel": "WEBHOOK",
"types": ["account_status_change"],
"config": {
"webhook": {
"url": "https://your-domain.com/webhooks/reap"
}
},
"createdAt": "2024-03-20T10:00:00Z"
}Key Output
| Parameter Name | Type | Description |
|---|---|---|
id | string | Unique identifier for the registered webhook subscription. Used as notificationId in all subsequent management calls |
channel | string | Notification delivery channel configured for the subscription (e.g. WEBHOOK) |
types | array of string | List of notification event types subscribed to |
config | object | Configuration details for the notification channel |
config.webhook.url | string | Webhook endpoint URL where notification events will be delivered |
createdAt | string | Timestamp indicating when the notification subscription was created (Format: ISO 8601) |
Each business is limited to a maximum of 10 webhook configurations. Additional registrations beyond this limit are rejected.
Step 2: List Webhook Subscriptions
Retrieve every webhook configuration registered against the business associated with the API key.
Call the List Webhook Subscriptions Endpoint
Use GET /notification to list all webhook configurations registered for the business.
Sample Request (cURL)
curl --request GET \
--url https://sandbox-compliance.api.reap.global/notification \
--header 'Accept: application/json' \
--header 'x-reap-api-key: ********'Key Input
| Parameter Name | Type | Description |
|---|---|---|
page | integer | Query parameter specifying the page number to retrieve |
limit | integer | Query parameter specifying number of records returned per page |
Sample Response
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"channel": "WEBHOOK",
"types": ["account_status_change"],
"config": {
"webhook": {
"url": "https://api.example.com/webhooks/reap"
}
},
"createdAt": "2024-03-20T10:00:00Z"
}
],
"meta": {
"itemCount": 1,
"totalItems": 1,
"itemsPerPage": 10,
"totalPages": 1,
"currentPage": 1
}
}Key Output
| Parameter Name | Type | Description |
|---|---|---|
items | array of object | Array of notification configurations registered for the authenticated business |
items[].id | string | Unique identifier for the notification configuration |
items[].channel | string | Notification delivery channel configured for the subscription (e.g. WEBHOOK) |
items[].types | array of string | List of notification event types subscribed to |
items[].config | object | Channel-specific configuration. For webhooks, contains the webhook.url property |
items[].config.webhook.url | string | Webhook endpoint URL where notification events will be delivered |
items[].createdAt | string | Timestamp indicating when the notification configuration was created (Format: ISO 8601) |
meta | object | Pagination metadata for the returned result set |
meta (object)
meta (object)| Parameter Name | Type | Description |
|---|---|---|
itemCount | number | Number of records returned on the current page |
totalItems | number | Total number of notification configurations available |
itemsPerPage | number | Maximum number of records returned per page |
totalPages | number | Total number of pages available |
currentPage | number | Current page number returned in the response |
Step 3: Get a Webhook Subscription
Retrieve the details of a single webhook configuration by its notificationId.
Call the Get Webhook Subscription Endpoint
Use GET /notification/notificationId to retrieve the configuration of a single webhook subscription.
Sample Request (cURL)
curl --request GET \
--url https://sandbox-compliance.api.reap.global/notification/notificationId \
--header 'Accept: application/json' \
--header 'x-reap-api-key: ********'Key Input
| Parameter Name | Type | Description |
|---|---|---|
notificationId | string | Path parameter specifying the UUID of the webhook subscription to retrieve as returned during registration |
Sample Response
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"channel": "WEBHOOK",
"types": ["account_status_change"],
"config": {
"webhook": {
"url": "https://api.example.com/webhooks/reap"
}
},
"createdAt": "2024-03-20T10:00:00Z"
}Key Output
| Parameter Name | Type | Description |
|---|---|---|
id | string | Unique identifier for the notification configuration |
channel | string | Notification delivery channel configured for the subscription (e.g. WEBHOOK) |
types | array of string | List of notification event types subscribed to |
config | object | Channel-specific configuration for webhooks containing the webhook.url property |
config.webhook.url | string | Webhook endpoint URL where notification events will be delivered |
createdAt | string | Timestamp indicating when the notification configuration was created (Format: ISO 8601) |
Step 4: Update a Webhook Subscription
Update an existing webhook configuration to change the destination URL, channel, or subscribed event types.
Call the Update Webhook Subscription Endpoint
Use PUT /notification/notificationId to update an existing webhook configuration.
Sample Request (cURL)
curl --request PUT \
--url https://sandbox-compliance.api.reap.global/notification/notificationId \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'x-reap-api-key: ********' \
--data '{
"webhookUrl": "https://your-updated-domain.com/webhooks/reap",
"notificationChannel": "WEBHOOK",
"notificationTypes": ["account_status_change"]
}'Key Input
| Parameter Name | Type | Description |
|---|---|---|
webhookUrl | string | Updated HTTPS URL where Reap will deliver event payloads. Must be publicly accessible |
Sample Response
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"channel": "WEBHOOK",
"types": ["account_status_change"],
"config": {
"webhook": {
"url": "https://api.example.com/webhooks/reap/updated"
}
},
"createdAt": "2024-03-20T10:00:00Z"
}Key Output
| Parameter Name | Type | Description |
|---|---|---|
id | string | Unique identifier for the notification configuration |
channel | string | Notification delivery channel configured for the subscription (e.g. WEBHOOK) |
types | array of string | List of notification event types subscribed to |
config | object | Channel-specific configuration for webhooks containing the webhook.url property |
config.webhook.url | string | Updated webhook endpoint URL where notification events will be delivered |
createdAt | string | Timestamp indicating when the notification configuration was created (Format: ISO 8601) |
Step 5: Delete a Webhook Subscription
Remove an existing webhook configuration so Reap stops delivering events to the registered URL.
Call the Delete Webhook Subscription Endpoint
Use DELETE /notification/notificationId to remove an existing webhook configuration.
Sample Request (cURL)
curl --request DELETE \
--url https://sandbox-compliance.api.reap.global/notification/notificationId \
--header 'Accept: application/json' \
--header 'x-reap-api-key: ********'Key Input
| Parameter Name | Type | Description |
|---|---|---|
notificationId | string | Path parameter specifying the UUID of the webhook subscription to delete |
Sample Response
No ContentA successful deletion returns
204 No Contentwith an empty response body. Once deleted, Reap stops delivering events to the previously registered URL and thenotificationIdcan no longer be retrieved viaGET /notification/notificationId.
Step 6: Verify the Webhook Signature
Every webhook request delivered by Reap includes a signature in the reap-signature header generated using RSA-SHA512. The integrator must verify each request against the raw JSON payload using the environment-specific RSA public key before processing the event.
Signature Algorithm
| Property | Value |
|---|---|
| Algorithm | RSA-SHA512 |
| Signature header | reap-signature |
| Signed content | Raw JSON request body delivered by Reap |
| Encoding | Base64-encoded signature value |
Public Keys for Signature Validation
Use the public key matching the environment from which the webhook is delivered.
Sandbox Public Key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsI0a/jqvSM6Z9gTLVMpD
4hLZ0n1WWuSNMwkqNH8s+E6tnBXx6nETgAJKwjdUagwgkySI74rwkCvPqVE0sm9c
iD8oi7XM+X8ybTET8fmVVG5sr12hJX5jQjjBUXzIuuqx5NJt7lFyo2yNrNzCSzuD
AhEa22Gkw43WWZoAVkNXlrfiyprKMfpjf7S4LUsRI/Y6MGyYmfm1olzYksymcaU+
2edfxoB2qZmezyEJM6CPkL2zt8UnnoS+kf/rbmHk+aKf8DW8v+XjeyQSxuclRZi/
IS589AACMygPvsO9KYzMoxmxNLrDcDnlo8+IKHQwE1RLoGC+EzJ0lDxWOEFZMRiE
xwIDAQAB
-----END PUBLIC KEY-----
Production Public Key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5JUURpniA359qJLwB9JW
6tFAhc4ChqBiGSBaFTkgmK/XCrV8e/N7q57qq4DwymDk5+ALw8D6cKeG2QkWPDeB
n3ly96sR14+8+2GfS7z82A194V9xEpZQfjF6DeMhidFjhINAAzJHPDiM7QCk9Dh4
/Ny065vzZb0O3ek9Ivs6sbmOKXa/pGACN3k30XLkPu2XxBfeZN1rCFhdwE/wa7Bf
h5AKiA104ais19ct5uf4vNkjG5DwevFK9WiqRVxwzadOyXCk4AdksdFx8ZkOuYWh
rCdIt3Dc+pErfKIHloJ7kqA/8kiWWOP6fWbSSWrEtpLX5ieVsXnqhOYq8xA5WvEo
HwIDAQAB
-----END PUBLIC KEY-----
Sample Verification Implementation (Node.js)
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, publicKey) {
const verifier = crypto.createVerify('RSA-SHA512');
verifier.update(JSON.stringify(payload));
verifier.end();
return verifier.verify(publicKey, signature, 'base64');
}
// Webhook handler
app.post('/webhooks/reap', (req, res) => {
const signature = req.headers['reap-signature'];
const publicKey = getPublicKeyForEnvironment(); // sandbox or production
if (!verifyWebhookSignature(req.body, signature, publicKey)) {
return res.status(401).send('Invalid signature');
}
// Process the verified event
console.log('Webhook verified successfully');
res.status(200).send('OK');
});
function getPublicKeyForEnvironment() {
if (process.env.NODE_ENV === 'production') {
return `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5JUURpniA359qJLwB9JW
6tFAhc4ChqBiGSBaFTkgmK/XCrV8e/N7q57qq4DwymDk5+ALw8D6cKeG2QkWPDeB
n3ly96sR14+8+2GfS7z82A194V9xEpZQfjF6DeMhidFjhINAAzJHPDiM7QCk9Dh4
/Ny065vzZb0O3ek9Ivs6sbmOKXa/pGACN3k30XLkPu2XxBfeZN1rCFhdwE/wa7Bf
h5AKiA104ais19ct5uf4vNkjG5DwevFK9WiqRVxwzadOyXCk4AdksdFx8ZkOuYWh
rCdIt3Dc+pErfKIHloJ7kqA/8kiWWOP6fWbSSWrEtpLX5ieVsXnqhOYq8xA5WvEo
HwIDAQAB
-----END PUBLIC KEY-----`;
}
return `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsI0a/jqvSM6Z9gTLVMpD
4hLZ0n1WWuSNMwkqNH8s+E6tnBXx6nETgAJKwjdUagwgkySI74rwkCvPqVE0sm9c
iD8oi7XM+X8ybTET8fmVVG5sr12hJX5jQjjBUXzIuuqx5NJt7lFyo2yNrNzCSzuD
AhEa22Gkw43WWZoAVkNXlrfiyprKMfpjf7S4LUsRI/Y6MGyYmfm1olzYksymcaU+
2edfxoB2qZmezyEJM6CPkL2zt8UnnoS+kf/rbmHk+aKf8DW8v+XjeyQSxuclRZi/
IS589AACMygPvsO9KYzMoxmxNLrDcDnlo8+IKHQwE1RLoGC+EzJ0lDxWOEFZMRiE
xwIDAQAB
-----END PUBLIC KEY-----`;
}Sample Verification Implementation (Python)
import json
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
def verify_webhook_signature(payload, signature, public_key_pem):
try:
public_key = serialization.load_pem_public_key(public_key_pem.encode())
signature_bytes = base64.b64decode(signature)
public_key.verify(
signature_bytes,
json.dumps(payload, separators=(',', ':')).encode(),
padding.PKCS1v15(),
hashes.SHA512()
)
return True
except Exception:
return False
# Flask webhook handler
@app.route('/webhooks/reap', methods=['POST'])
def handle_webhook():
signature = request.headers.get('reap-signature')
public_key = get_public_key_for_environment()
if not verify_webhook_signature(request.json, signature, public_key):
return 'Invalid signature', 401
# Process the verified event
print('Webhook verified successfully')
return 'OK', 200Always verify the signature against the original JSON payload received in the request body and not against a reconstructed object. Reconstructing the payload may alter key ordering or whitespace and cause verification to fail.
Webhook Endpoint Requirements
The webhook endpoint registered with Reap must comply with the following requirements.
Technical Requirements
| Requirement | Detail |
|---|---|
| Protocol | HTTPS is required for all webhook endpoints |
| Response status | The endpoint must return 200 OK for successfully received events |
| Response time | The endpoint must respond within 5 seconds |
| Response body | The response body is ignored — only the 200 OK status code is required |
| Signature verification | Verify the webhook signature using Reap's RSA public key for the relevant environment |
| Environment validation | Validate the endpoint in the sandbox environment before enabling the webhook subscription in production |
Rate Limits and Constraints
| Constraint | Limit |
|---|---|
| Maximum subscriptions | Up to 10 webhook configurations per business |
| Endpoint response timeout | 5 seconds per delivery attempt |
| Retry policy | Failed deliveries are retried using exponential backoff |
Security Best Practices
- Always verify the signature before processing webhook data
- Use HTTPS for the webhook endpoint and present a valid TLS certificate
- Validate the structure and content of every incoming payload
- Log every webhook event for debugging and audit purposes
- Implement idempotency at the consumer to safely handle duplicate deliveries from retries
- Secure the API keys used for subscription management and rotate them regularly
Testing Your Webhook
Validate the webhook integration end to end in the sandbox environment before enabling delivery in production.
Webhook Endpoint Validation
The webhook endpoint must:
- Be reachable from the public internet via HTTPS
- Return
200 OKfor validPOSTrequests - Handle JSON request payloads correctly
- Respond within 5 seconds
- Implement RSA-SHA512 signature verification using the sandbox public key
Sample Test Endpoint
// Simple test endpoint
app.post('/webhooks/reap', (req, res) => {
console.log('Received webhook:', JSON.stringify(req.body, null, 2));
console.log('Headers:', req.headers);
// Always verify the signature in production
const signature = req.headers['reap-signature'];
if (signature && !verifyWebhookSignature(req.body, signature, publicKey)) {
return res.status(401).send('Invalid signature');
}
res.status(200).send('OK');
});Testing Checklist
- Webhook URL is reachable over HTTPS from the public internet
- Endpoint returns
200 OKfor validPOSTrequests within 5 seconds - Signature verification is implemented using the environment-specific public key
- Error handling rejects requests with an invalid or missing signature
- Logging is configured for incoming requests and verification outcomes
- Webhook registration via
POST /notificationreturned a successful response
Scenarios
Scenario: First-Time Webhook Setup
- Generate a sandbox API key from the Reap Card Issuance Dashboard
- Provision an HTTPS endpoint and configure the sandbox public key for signature verification
- Register the webhook via
POST /notificationsubscribing toaccount_status_change - Validate end-to-end delivery in the sandbox environment
- Repeat the registration in production using the production API key and production public key
Scenario: Update the Webhook URL
- Retrieve the existing configuration via
GET /notification/notificationId - Update the destination via
PUT /notification/notificationIdwith the newwebhookUrl - Confirm signature verification continues to succeed against the same environment public key
Scenario: Remove a Webhook Subscription
- Remove the configuration via
DELETE /notification/notificationIdto stop event delivery - Confirm via
GET /notificationthat the subscription is no longer listed
Common Errors
| Error | Cause | Resolution |
|---|---|---|
| Webhook not receiving events | Endpoint unreachable, HTTPS misconfigured, or subscribed to the wrong event type | Confirm the endpoint is reachable over HTTPS and the subscription includes account_status_change |
| Signature verification failing | Wrong environment public key, parsed payload re-serialised, or incorrect signature header | Verify against the raw JSON body using the matching environment public key and read the reap-signature header |
| Webhook timeout | Endpoint did not return 200 OK within 5 seconds | Process webhook events asynchronously and return 200 OK immediately after receipt |
| 401 Unauthorized | Missing or invalid API key when calling the /notification endpoints | Check x-reap-api-key and confirm the API key matches the environment |
| Webhook configuration limit reached | Business already has 10 webhook configurations registered | Delete an unused configuration via DELETE /notification/notificationId before registering a new one |
TL;DR
- Webhooks are available only for the KYCaaS and Universal KYC verification methods and currently support the
account_status_changeevent type - Register a webhook via
POST /notificationwithwebhookUrl,notificationChannel: "WEBHOOK", andnotificationTypes: ["account_status_change"] - Manage subscriptions via
GET /notification,GET /notification/notificationId,PUT /notification/notificationId, andDELETE /notification/notificationId - Webhook endpoints must use HTTPS and return
200 OKwithin 5 seconds, and failed deliveries are retried with exponential backoff - Verify every request using RSA-SHA512 against the raw JSON body and the environment-specific public key from the
reap-signatureheader - Each business is limited to a maximum of 10 webhook configurations
- Validate the webhook integration in the sandbox environment before enabling delivery in production
Support
Contact your Reap Implementation Manager for any webhook setup, signature verification, or delivery issues. Include the webhook URL, the
notificationIdreturned at registration, the environment (sandbox or production), and any relevant error messages or logs when raising a support request.
Updated 3 days ago
