Documentation Index Fetch the complete documentation index at: https://partner-docs.contro.dev/llms.txt
Use this file to discover all available pages before exploring further.
Webhooks let you receive HTTP callbacks when events occur in your partner account - such as card transactions, KYC status changes, or balance updates.
Get current config
cURL
SDK (Node)
SDK (Python)
curl https://api.contro.me/v1/partner/webhooks/config \
-H "x-contro-api-key: $CONTRO_API_KEY "
Response:
{
"webhookUrl" : "https://your-app.com/webhooks/contro" ,
"webhookSecret" : "whsec_..." ,
"subscribedEvents" : [ "card.transaction" , "cardholder.kyc.updated" ]
}
Update config
cURL
SDK (Node)
SDK (Python)
curl -X PATCH https://api.contro.me/v1/partner/webhooks/config \
-H "x-contro-api-key: $CONTRO_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"webhookUrl": "https://your-app.com/webhooks/contro",
"webhookSecret": "whsec_your_secret_min_16_chars",
"subscribedEvents": ["card.transaction", "cardholder.kyc.updated", "balance.low"]
}'
Field Type Description webhookUrlstring HTTPS URL to receive events. Must use https://. Example: "https://your-app.com/webhooks/contro" webhookSecretstring Secret for HMAC-SHA256 signature verification. Min 16 characters. Example: "whsec_your_secret_min_16_chars" subscribedEventsstring[] Event types to subscribe to. Example: ["card.transaction", "cardholder.kyc.updated"]
Event types
Event Description card.transactionCard transaction lifecycle event (authorized, settled, declined, reversed) card.issuedA new card was issued card.status.changedA card was activated, frozen, unfrozen, or cancelled card.3ds_otp3DS one-time passcode for partner-issued cards — deliver to cardholder within 60s cardholder.kyc.updatedKYC status changed (approved, rejected) cardholder.createdA new cardholder was created balance.lowBalance fell below threshold balance.top_upBalance was topped up kyc_session.completedA KYC session was approved kyc_session.failedA KYC session was rejected
Verifying webhook signatures
Every webhook request includes an HMAC-SHA256 signature in the X-Contro-Signature header. The signature format is t={timestamp},v1={hmac}, where the HMAC is computed over {timestamp}.{body}.
import crypto from "node:crypto" ;
function verifyWebhookSignature ( body , signatureHeader , secret ) {
const parts = Object . fromEntries (
signatureHeader . split ( "," ). map (( p ) => p . split ( "=" , 2 ))
);
const timestamp = parts . t ;
const receivedHmac = parts . v1 ;
const expected = crypto
. createHmac ( "sha256" , secret )
. update ( ` ${ timestamp } . ${ body } ` )
. digest ( "hex" );
return crypto . timingSafeEqual (
Buffer . from ( receivedHmac ),
Buffer . from ( expected )
);
}
// In your webhook handler:
app . post ( "/webhooks/contro" , ( req , res ) => {
const body = JSON . stringify ( req . body );
const signature = req . headers [ "x-contro-signature" ];
if ( ! verifyWebhookSignature ( body , signature , WEBHOOK_SECRET )) {
return res . status ( 401 ). send ( "Invalid signature" );
}
// Process the event - event type is in the X-Contro-Event header
const eventType = req . headers [ "x-contro-event" ];
console . log ( "Event type:" , eventType );
res . status ( 200 ). send ( "OK" );
});
Always verify webhook signatures before processing events. Unverified webhooks could be spoofed by attackers.
Retry policy
Failed deliveries (non-2xx responses or timeouts) are retried with exponential backoff:
Attempt Delay 1st retry 1 minute 2nd retry 5 minutes 3rd retry 30 minutes 4th retry 2 hours 5th retry 24 hours
After 5 failed retries, the event is marked as failed. You can manually retry failed events.
List webhook events
View the delivery history for your webhooks:
cURL
SDK (Node)
SDK (Python)
curl "https://api.contro.me/v1/partner/webhooks/events?limit=20&status=failed" \
-H "x-contro-api-key: $CONTRO_API_KEY "
Query parameters
Parameter Type Description pageinteger Page number (default 1). limitinteger Items per page (1–100, default 20). Example: 50 statusstring Filter by delivery status. One of pending, delivered, failed. eventTypestring Filter by event type. Example: "card.transaction". fromstring ISO 8601 start timestamp (inclusive) on createdAt. tostring ISO 8601 end timestamp (inclusive) on createdAt.
Event fields
Field Type Description idstring Event ID. Example: "evt_abc123" eventTypestring Event type. One of card.transaction, card.issued, card.status.changed, cardholder.kyc.updated, cardholder.created, balance.low, balance.top_up, kyc_session.completed, kyc_session.failed statusstring Delivery status. One of pending, delivered, failed attemptCountnumber Number of delivery attempts made. Example: 3 lastAttemptAtstring | null ISO 8601 timestamp of last delivery attempt, or null. Example: "2026-03-20T14:30:00Z" nextRetryAtstring | null ISO 8601 timestamp of the next scheduled retry, or null if no retry is pending. Example: "2026-03-20T15:00:00Z" lastResponseStatusnumber | null HTTP status code from the last delivery attempt, or null. Example: 500 createdAtstring ISO 8601 event creation timestamp. Example: "2026-03-20T14:30:00Z"
Get a webhook event
Fetch a single delivery event including the full payload and the last response body. Both fields are redacted server-side to mask secrets, tokens, and other sensitive values.
cURL
SDK (Node)
SDK (Python)
curl https://api.contro.me/v1/partner/webhooks/events/{eventId} \
-H "x-contro-api-key: $CONTRO_API_KEY "
Additional response fields
In addition to the list fields above, the detail response includes:
Field Type Description payloadstring Redacted JSON body that was (or will be) sent to your endpoint. lastResponseBodystring | null Redacted response body from the destination, or null. webhookUrlstring | null Destination URL the event was delivered to, or null if not configured.
Retry a failed event
Manually retry delivery of a failed event:
cURL
SDK (Node)
SDK (Python)
curl -X POST https://api.contro.me/v1/partner/webhooks/events/{eventId}/retry \
-H "x-contro-api-key: $CONTRO_API_KEY "