Webhooks API Reference
All webhook endpoints are mounted at /v1/webhooks. Requires Authorization: Bearer session token or X-API-Key.
Endpoints summary
| Method | Path | Description |
|---|---|---|
GET | /v1/webhooks | Get current webhook configuration |
PUT | /v1/webhooks | Create or update webhook configuration |
POST | /v1/webhooks/test | Send a test webhook to the configured URL |
GET | /v1/webhooks/deliveries | List delivery jobs (paginated) |
GET | /v1/webhooks/deliveries/{job_id} | Get delivery job detail with all attempt logs |
GET /v1/webhooks
Returns the current webhook configuration for the authenticated user.
Response (200 OK):
{
"success": true,
"data": {
"url": "https://yourserver.com/tcf-webhook",
"is_active": true,
"has_secret": true,
"events": ["payment.completed", "payment.expired", "withdrawal.completed"],
"updated_at": "2026-05-15T09:00:00Z"
}
}
has_secretis a boolean — the secret value is never returned via the API.
PUT /v1/webhooks
Create or update the webhook configuration. This is an upsert — if no config exists it is created; if one exists it is updated.
Request body:
| Field | Type | Required | Constraints |
|---|---|---|---|
url | string | Yes | Must start with https:// |
secret | string | No | If omitted, a secret is auto-generated. Provide to set your own. |
is_active | boolean | No | Default: true |
events | array of strings | No | Event type strings or ["*"] for all. Default: ["*"] |
Example request:
{
"url": "https://yourserver.com/tcf-webhook",
"secret": "my-strong-secret-at-least-32-chars",
"is_active": true,
"events": ["payment.completed", "payment.expired_partial", "withdrawal.completed"]
}Response (200 OK):
{
"success": true,
"data": {
"url": "https://yourserver.com/tcf-webhook",
"is_active": true,
"has_secret": true,
"events": ["payment.completed", "payment.expired_partial", "withdrawal.completed"],
"updated_at": "2026-05-16T12:00:00Z"
}
}Error codes:
| Code | Condition |
|---|---|
VALIDATION_ERROR | URL is not HTTPS or events list contains an unknown event type |
POST /v1/webhooks/test
Send a synthetic test webhook delivery to your configured URL. Useful for verifying your endpoint and signature verification code.
The test payload is shaped like a payment.completed event with synthetic (non-real) data.
Request body: none required
Response (200 OK):
{
"success": true,
"data": {
"delivered": true,
"status_code": 200,
"response_body": "OK",
"payload_sent": {
"event": "payment.completed",
"timestamp": "2026-05-16T12:00:00Z",
"data": { "payment_id": "test-00000000-...", "status": "COMPLETED", ... }
}
}
}Error codes:
| Code | Condition |
|---|---|
NOT_FOUND | No webhook configuration exists yet |
VALIDATION_ERROR | Webhook URL is not configured or inactive |
GET /v1/webhooks/deliveries
List webhook delivery jobs for the authenticated user, newest first.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: pending, success, failed, permanently_failed |
event | string | Filter by event type (e.g. payment.completed) |
page | integer | Default: 1 |
per_page | integer | Default: 20, max: 100 |
Response (200 OK):
{
"success": true,
"data": {
"jobs": [
{
"job_id": "d1e2f3a4-...",
"event": "payment.completed",
"status": "success",
"attempt_count": 1,
"source_type": "payment",
"source_id": "9f1b2c3d-...",
"created_at": "2026-05-16T12:05:00Z",
"last_attempt_at": "2026-05-16T12:05:02Z",
"last_response_status": 200
}
],
"pagination": { "page": 1, "per_page": 20, "total": 42, "total_pages": 3 }
}
}GET /v1/webhooks/deliveries/
Get full detail for a delivery job, including all attempt logs.
Response (200 OK):
{
"success": true,
"data": {
"job_id": "d1e2f3a4-...",
"event": "payment.completed",
"status": "success",
"attempt_count": 1,
"max_attempts": 10,
"payload": { "event": "payment.completed", ... },
"logs": [
{
"attempted_at": "2026-05-16T12:05:02Z",
"response_status": 200,
"response_body": "OK",
"error_message": null,
"duration_ms": 145
}
]
}
}
