Webhook endpoints
Register event URLs, rotate secrets, inspect deliveries and redeliver.
List webhook endpoints
GET/v1/webhook_endpoints
All URLs receiving events.
Returns
200 · A page of WebhookEndpoint plus nextCursor for the next page.
curl https://api.hensa.example/v1/webhook_endpoints \ -H "Authorization: Bearer $HENSA_API_KEY"const res = await fetch('https://api.hensa.example/v1/webhook_endpoints', { method: 'GET', headers: { Authorization: `Bearer ${process.env.HENSA_API_KEY}`, },})const data = await res.json()<?php$ch = curl_init('https://api.hensa.example/v1/webhook_endpoints');curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('HENSA_API_KEY'), ],]);$data = json_decode(curl_exec($ch), true);import os, requests
res = requests.get( "https://api.hensa.example/v1/webhook_endpoints", headers={ "Authorization": f"Bearer {os.environ['HENSA_API_KEY']}", }, timeout=10,)res.raise_for_status(){ "data": [ { "id": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "url": "https://cuahang.vn/webhooks/hensa", "events": [ "payment_request.paid", "bank_transaction.created" ], "status": "active", "secretLast4": "9f2a", "createdAt": "2026-11-03T07:00:00Z" } ]}/v1/webhook_endpointsCreate a webhook endpoint
POST/v1/webhook_endpoints
The URL must be public HTTPS (private addresses are rejected). The signing secret (whsec_…) is returned once – store it now.
Request body
urlstringrequiredPublic HTTPS URL that will receive events.
eventsstring[]requiredEvents to receive (at least one).
Values:
bank_transaction.createdpayment_request.paidpayment_request.partially_paidpayment_request.expiredbank_connection.status_changed
Returns
201 · WebhookEndpoint + secret
Possible errors
validation_error400 Invalid request data – seemessage.url_not_https422 Webhook URLs must use HTTPS.url_private_address422 The URL resolves to a private address – not allowed.
curl -X POST https://api.hensa.example/v1/webhook_endpoints \ -H "Authorization: Bearer $HENSA_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"url":"https://cuahang.vn/webhooks/hensa","events":["payment_request.paid","bank_transaction.created"]}'const res = await fetch('https://api.hensa.example/v1/webhook_endpoints', { method: 'POST', headers: { Authorization: `Bearer ${process.env.HENSA_API_KEY}`, 'Idempotency-Key': crypto.randomUUID(), 'Content-Type': 'application/json' }, body: JSON.stringify({ "url": "https://cuahang.vn/webhooks/hensa", "events": [ "payment_request.paid", "bank_transaction.created" ] })})const data = await res.json()<?php$ch = curl_init('https://api.hensa.example/v1/webhook_endpoints');curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('HENSA_API_KEY'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => '{"url":"https://cuahang.vn/webhooks/hensa","events":["payment_request.paid","bank_transaction.created"]}',]);$data = json_decode(curl_exec($ch), true);import os, uuid, requests
res = requests.post( "https://api.hensa.example/v1/webhook_endpoints", headers={ "Authorization": f"Bearer {os.environ['HENSA_API_KEY']}", "Idempotency-Key": str(uuid.uuid4()), }, json={ "url": "https://cuahang.vn/webhooks/hensa", "events": [ "payment_request.paid", "bank_transaction.created" ] }, timeout=10,)res.raise_for_status(){ "endpoint": { "id": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "url": "https://cuahang.vn/webhooks/hensa", "events": [ "payment_request.paid", "bank_transaction.created" ], "status": "active", "secretLast4": "9f2a", "createdAt": "2026-11-03T07:00:00Z" }, "secret": "…"}/v1/webhook_endpointsDelete a webhook endpoint
DELETE/v1/webhook_endpoints/{id}
Stops sending events to this URL immediately.
Parameters
idstring · pathrequiredEndpoint ID.
Returns
204 · No content.
Possible errors
not_found404 Not found (or not owned by this key's store).
curl -X DELETE https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K \ -H "Authorization: Bearer $HENSA_API_KEY"const res = await fetch('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K', { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.HENSA_API_KEY}`, },})// 204 No Content<?php$ch = curl_init('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K');curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'DELETE', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('HENSA_API_KEY'), ],]);$data = json_decode(curl_exec($ch), true);import os, requests
res = requests.delete( "https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", headers={ "Authorization": f"Bearer {os.environ['HENSA_API_KEY']}", }, timeout=10,)res.raise_for_status()/v1/webhook_endpoints/Rotate the signing secret
POST/v1/webhook_endpoints/{id}/rotate_secret
Creates a new secret. The old one stays valid for 24 hours – meanwhile each event carries two v1 signatures so you can switch without downtime.
Parameters
idstring · pathrequiredEndpoint ID.
Returns
200 · WebhookEndpoint + secret
Possible errors
not_found404 Not found (or not owned by this key's store).
curl -X POST https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/rotate_secret \ -H "Authorization: Bearer $HENSA_API_KEY"const res = await fetch('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/rotate_secret', { method: 'POST', headers: { Authorization: `Bearer ${process.env.HENSA_API_KEY}`, },})const data = await res.json()<?php$ch = curl_init('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/rotate_secret');curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('HENSA_API_KEY'), ],]);$data = json_decode(curl_exec($ch), true);import os, requests
res = requests.post( "https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/rotate_secret", headers={ "Authorization": f"Bearer {os.environ['HENSA_API_KEY']}", }, timeout=10,)res.raise_for_status(){ "endpoint": { "id": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "url": "https://cuahang.vn/webhooks/hensa", "events": [ "payment_request.paid", "bank_transaction.created" ], "status": "active", "secretLast4": "9f2a", "createdAt": "2026-11-03T07:00:00Z" }, "secret": "…"}/v1/webhook_endpoints//rotate_secretSend a test event
POST/v1/webhook_endpoints/{id}/test
Sends a signed sample event to the endpoint right away and returns the result.
Parameters
idstring · pathrequiredEndpoint ID.
Returns
200 · WebhookDelivery
Possible errors
not_found404 Not found (or not owned by this key's store).
curl -X POST https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/test \ -H "Authorization: Bearer $HENSA_API_KEY"const res = await fetch('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/test', { method: 'POST', headers: { Authorization: `Bearer ${process.env.HENSA_API_KEY}`, },})const data = await res.json()<?php$ch = curl_init('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/test');curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('HENSA_API_KEY'), ],]);$data = json_decode(curl_exec($ch), true);import os, requests
res = requests.post( "https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/test", headers={ "Authorization": f"Bearer {os.environ['HENSA_API_KEY']}", }, timeout=10,)res.raise_for_status(){ "id": "whd_01JD7QC4V6X8Z0B2D4F6H8K0MP", "endpointId": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "eventType": "payment_request.paid", "status": "succeeded", "httpStatus": 200, "durationMs": 142, "attempt": 1, "createdAt": "2026-11-03T08:03:12Z"}/v1/webhook_endpoints//testList deliveries
GET/v1/webhook_endpoints/{id}/deliveries
Every delivery attempt in the last 30 days, including failures.
Parameters
idstring · pathrequiredEndpoint ID.
limitinteger · queryItems per page (1–100, default 25).
cursorstring · queryThe
nextCursorvalue from the previous page.
Returns
200 · A page of WebhookDelivery plus nextCursor for the next page.
Possible errors
not_found404 Not found (or not owned by this key's store).
curl https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/deliveries \ -H "Authorization: Bearer $HENSA_API_KEY"const res = await fetch('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/deliveries', { method: 'GET', headers: { Authorization: `Bearer ${process.env.HENSA_API_KEY}`, },})const data = await res.json()<?php$ch = curl_init('https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/deliveries');curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('HENSA_API_KEY'), ],]);$data = json_decode(curl_exec($ch), true);import os, requests
res = requests.get( "https://api.hensa.example/v1/webhook_endpoints/whe_01JD7R1S3T5V7X9Z1B3D5F7H9K/deliveries", headers={ "Authorization": f"Bearer {os.environ['HENSA_API_KEY']}", }, timeout=10,)res.raise_for_status(){ "data": [ { "id": "whd_01JD7QC4V6X8Z0B2D4F6H8K0MP", "endpointId": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "eventType": "payment_request.paid", "status": "succeeded", "httpStatus": 200, "durationMs": 142, "attempt": 1, "createdAt": "2026-11-03T08:03:12Z" } ], "nextCursor": "…"}/v1/webhook_endpoints//deliveriesRedeliver
POST/v1/webhook_deliveries/{id}/redeliver
Resends an event (within 30 days). Same event id – your system must be idempotent.
Parameters
idstring · pathrequiredDelivery ID.
Returns
200 · WebhookDelivery
Possible errors
not_found404 Not found (or not owned by this key's store).delivery_too_old422 Only events from the last 30 days can be redelivered.
curl -X POST https://api.hensa.example/v1/webhook_deliveries/whd_01JD7QC4V6X8Z0B2D4F6H8K0MP/redeliver \ -H "Authorization: Bearer $HENSA_API_KEY"const res = await fetch('https://api.hensa.example/v1/webhook_deliveries/whd_01JD7QC4V6X8Z0B2D4F6H8K0MP/redeliver', { method: 'POST', headers: { Authorization: `Bearer ${process.env.HENSA_API_KEY}`, },})const data = await res.json()<?php$ch = curl_init('https://api.hensa.example/v1/webhook_deliveries/whd_01JD7QC4V6X8Z0B2D4F6H8K0MP/redeliver');curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('HENSA_API_KEY'), ],]);$data = json_decode(curl_exec($ch), true);import os, requests
res = requests.post( "https://api.hensa.example/v1/webhook_deliveries/whd_01JD7QC4V6X8Z0B2D4F6H8K0MP/redeliver", headers={ "Authorization": f"Bearer {os.environ['HENSA_API_KEY']}", }, timeout=10,)res.raise_for_status(){ "id": "whd_01JD7QC4V6X8Z0B2D4F6H8K0MP", "endpointId": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "eventType": "payment_request.paid", "status": "succeeded", "httpStatus": 200, "durationMs": 142, "attempt": 1, "createdAt": "2026-11-03T08:03:12Z"}/v1/webhook_deliveries//redeliverObjects
WebhookEndpoint
idstringrequiredEndpoint ID.
urlstringrequiredPublic HTTPS URL receiving events.
eventsstring[]requiredSubscribed events.
Values:
bank_transaction.createdpayment_request.paidpayment_request.partially_paidpayment_request.expiredbank_connection.status_changedstatusstringrequiredactive·failing(alerts sent) ·disabled.secretLast4stringrequiredLast 4 characters of the signing secret – for identification.
createdAtstringrequiredCreation time.
{ "id": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "url": "https://cuahang.vn/webhooks/hensa", "events": [ "payment_request.paid", "bank_transaction.created" ], "status": "active", "secretLast4": "9f2a", "createdAt": "2026-11-03T07:00:00Z"}WebhookDelivery
idstringrequiredDelivery ID.
endpointIdstringrequiredTarget endpoint.
eventTypestringrequiredEvent type.
Values:
bank_transaction.createdpayment_request.paidpayment_request.partially_paidpayment_request.expiredbank_connection.status_changedstatusstringrequiredsucceeded·failed·retrying.httpStatusinteger | nullrequiredHTTP status your server returned.
Values:
durationMsinteger | nullrequiredResponse time (ms).
Values:
attemptintegerrequiredAttempt number (1–8).
createdAtstringrequiredDelivery time.
{ "id": "whd_01JD7QC4V6X8Z0B2D4F6H8K0MP", "endpointId": "whe_01JD7R1S3T5V7X9Z1B3D5F7H9K", "eventType": "payment_request.paid", "status": "succeeded", "httpStatus": 200, "durationMs": 142, "attempt": 1, "createdAt": "2026-11-03T08:03:12Z"}