This document provides a complete reference for the Hookbase webhook subscription API endpoints.
All API endpoints require authentication using a Bearer token or API key:
# Using Bearer token
curl -H "Authorization: Bearer {token}" ...
# Using API key
curl -H "x-api-key: whr_xxx" ...
https://api.hookbase.app/api/organizations/{orgId}
Replace {orgId} with your organization ID.
Send an event to all subscribed endpoints.
Field Type Required Description eventType string Yes Event type name (e.g., order.created ) payload any Yes Event payload (JSON-serializable) applicationId string No Target a specific application endpointId string No Target a specific endpoint idempotencyKey string No Unique key to prevent duplicate processing labels object No Key-value labels for filtering metadata object No Additional metadata stored with the event
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/send-event" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"eventType": "order.created",
"payload": {
"orderId": "ord_123",
"customerId": "cus_456",
"amount": 99.99
},
"idempotencyKey": "order-created-ord_123",
"labels": {
"region": "us-west",
"priority": "high"
}
}'
{
"data" : {
"eventId" : "evt_abc123" ,
"messagesQueued" : 3 ,
"endpoints" : [
{ "id" : "wh_ep_xxx" , "url" : "https://api.customer1.com/webhooks" },
{ "id" : "wh_ep_yyy" , "url" : "https://api.customer2.com/webhooks" },
{ "id" : "wh_ep_zzz" , "url" : "https://api.customer3.com/webhooks" }
]
}
}
Status Error Description 400 Invalid input Request body validation failed 404 Event type not found No enabled event type with this name 413 Payload too large Payload exceeds plan limit 415 Invalid Content-Type Content-Type must be application/json 429 Rate limit exceeded Too many events sent 429 Monthly limit exceeded Monthly message quota exceeded
Parameter Type Default Description category string - Filter by category isEnabled boolean - Filter by enabled status search string - Search by name limit integer 50 Max results (1-100) cursor string - Pagination cursor
curl "https://api.hookbase.app/api/organizations/{orgId}/event-types?category=orders&limit=20" \
-H "Authorization: Bearer {token}"
{
"data" : [
{
"id" : "evt_type_xxx" ,
"name" : "order.created" ,
"displayName" : "Order Created" ,
"description" : "Triggered when a new order is placed" ,
"category" : "orders" ,
"schema" : "{...}" ,
"examplePayload" : "{...}" ,
"isEnabled" : true ,
"isDeprecated" : false ,
"subscriptionCount" : 15 ,
"createdAt" : "2024-01-10T10:00:00Z"
}
],
"pagination" : {
"hasMore" : true ,
"nextCursor" : "evt_type_yyy"
}
}
GET /event-types/{eventTypeId}
{
"data" : {
"id" : "evt_type_xxx" ,
"name" : "order.created" ,
"displayName" : "Order Created" ,
"description" : "Triggered when a new order is placed" ,
"category" : "orders" ,
"schema" : "{ \" type \" : \" object \" , ...}" ,
"schemaVersion" : 2 ,
"examplePayload" : "{ \" orderId \" : \" ord_123 \" , ...}" ,
"documentationUrl" : "https://docs.example.com/events/order-created" ,
"isEnabled" : true ,
"isDeprecated" : false ,
"deprecatedAt" : null ,
"deprecatedMessage" : null ,
"createdAt" : "2024-01-10T10:00:00Z" ,
"updatedAt" : "2024-01-15T14:30:00Z"
}
}
Field Type Required Description name string Yes Unique name (lowercase, dot-separated) displayName string No Human-readable name description string No Description (max 1000 chars) category string No Category for grouping schema string No JSON Schema for validation examplePayload string No Example payload (JSON string) documentationUrl string No Link to documentation isEnabled boolean No Whether active (default: true)
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/event-types" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "payment.succeeded",
"displayName": "Payment Succeeded",
"description": "Triggered when a payment is successfully processed",
"category": "payments",
"schema": "{\"type\": \"object\", \"required\": [\"paymentId\", \"amount\"]}",
"examplePayload": "{\"paymentId\": \"pay_123\", \"amount\": 100.00}"
}'
{
"data" : {
"id" : "evt_type_xxx" ,
"name" : "payment.succeeded" ,
"displayName" : "Payment Succeeded" ,
"isEnabled" : true ,
"createdAt" : "2024-01-20T10:00:00Z"
}
}
PATCH /event-types/{eventTypeId}
Field Type Description displayName string Human-readable name description string Description category string Category schema string JSON Schema (increments schemaVersion) examplePayload string Example payload documentationUrl string Documentation URL isEnabled boolean Enable/disable isDeprecated boolean Mark as deprecated deprecatedMessage string Deprecation notice
curl -X PATCH "https://api.hookbase.app/api/organizations/{orgId}/event-types/{eventTypeId}" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"isDeprecated": true,
"deprecatedMessage": "Use payment.completed instead. Removal date: 2024-06-01"
}'
DELETE /event-types/{eventTypeId}
Note: This cascades to delete all subscriptions for this event type.
GET /webhook-applications
Parameter Type Default Description search string - Search by name isDisabled boolean - Filter by disabled status limit integer 50 Max results (1-100) cursor string - Pagination cursor orderBy string created_at Sort field order string desc Sort direction (asc/desc)
{
"data" : [
{
"id" : "wh_app_xxx" ,
"externalId" : "customer_123" ,
"name" : "Acme Corp" ,
"metadata" : { "plan" : "enterprise" },
"rateLimitPerSecond" : 100 ,
"rateLimitPerMinute" : 1000 ,
"rateLimitPerHour" : 10000 ,
"isDisabled" : false ,
"totalEndpoints" : 3 ,
"totalMessagesSent" : 15420 ,
"totalMessagesFailed" : 23 ,
"lastEventAt" : "2024-01-20T15:30:00Z" ,
"createdAt" : "2024-01-01T10:00:00Z"
}
],
"pagination" : {
"hasMore" : false ,
"nextCursor" : null
}
}
GET /webhook-applications/{applicationId}
GET /webhook-applications/by-external-id/{externalId}
Useful for looking up applications using your internal customer ID.
POST /webhook-applications
Field Type Required Description name string Yes Application name externalId string No Your internal customer ID metadata object No Custom metadata rateLimitPerSecond integer No Rate limit (default: 100) rateLimitPerMinute integer No Rate limit (default: 1000) rateLimitPerHour integer No Rate limit (default: 10000)
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-applications" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"externalId": "customer_123",
"metadata": {
"plan": "enterprise",
"accountManager": "[email protected] "
}
}'
PUT /webhook-applications/upsert
Create or update an application by external ID. Useful for syncing from your customer database.
Field Type Required Description externalId string Yes Your internal customer ID name string Yes Application name metadata object No Custom metadata rateLimitPerSecond integer No Rate limit rateLimitPerMinute integer No Rate limit rateLimitPerHour integer No Rate limit
{
"data" : { ... },
"created" : true
}
PATCH /webhook-applications/{applicationId}
Field Type Description name string Application name metadata object Custom metadata rateLimitPerSecond integer Rate limit rateLimitPerMinute integer Rate limit rateLimitPerHour integer Rate limit isDisabled boolean Disable/enable disabledReason string Reason for disabling
DELETE /webhook-applications/{applicationId}
Note: This cascades to delete all endpoints and subscriptions.
Parameter Type Default Description applicationId string - Filter by application isDisabled boolean - Filter by disabled status circuitState string - Filter by circuit state (closed/open/half_open) limit integer 50 Max results (1-100) cursor string - Pagination cursor
{
"data" : [
{
"id" : "wh_ep_xxx" ,
"applicationId" : "wh_app_yyy" ,
"url" : "https://api.customer.com/webhooks" ,
"description" : "Production endpoint" ,
"secretPrefix" : "whsec_abc123..." ,
"hasSecret" : true ,
"timeoutSeconds" : 30 ,
"isDisabled" : false ,
"isVerified" : true ,
"circuitState" : "closed" ,
"circuitFailureCount" : 0 ,
"totalMessages" : 1542 ,
"totalSuccesses" : 1520 ,
"totalFailures" : 22 ,
"avgResponseTimeMs" : 145 ,
"lastSuccessAt" : "2024-01-20T15:30:00Z" ,
"subscriptionCount" : 5 ,
"createdAt" : "2024-01-01T10:00:00Z"
}
],
"pagination" : {
"hasMore" : false ,
"nextCursor" : null
}
}
GET /webhook-endpoints/{endpointId}
Field Type Required Description applicationId string Yes Parent application ID url string Yes HTTPS endpoint URL description string No Description (max 500 chars) headers array No Custom headers to include timeoutSeconds integer No Request timeout (default: 30, max: 120) rateLimitPerSecond integer No Endpoint rate limit (0 = unlimited) circuitFailureThreshold integer No Failures to open circuit (default: 5) circuitSuccessThreshold integer No Successes to close circuit (default: 2) circuitCooldownSeconds integer No Cooldown period (default: 60)
{
"headers" : [
{ "name" : "X-Custom-Header" , "value" : "my-value" },
{ "name" : "Authorization" , "value" : "Bearer token123" }
]
}
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-endpoints" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "wh_app_xxx",
"url": "https://api.customer.com/webhooks",
"description": "Production webhook endpoint",
"timeoutSeconds": 30,
"headers": [
{"name": "X-API-Version", "value": "2024-01-01"}
],
"circuitFailureThreshold": 10
}'
{
"data" : {
"id" : "wh_ep_xxx" ,
"url" : "https://api.customer.com/webhooks" ,
"secret" : "whsec_abc123def456ghi789..." ,
"circuitState" : "closed"
},
"warning" : "Save the signing secret now. It will not be shown again."
}
PATCH /webhook-endpoints/{endpointId}
Field Type Description url string Endpoint URL description string Description headers array Custom headers timeoutSeconds integer Request timeout isDisabled boolean Disable/enable disabledReason string Reason for disabling rateLimitPerSecond integer Rate limit circuitFailureThreshold integer Circuit breaker config circuitSuccessThreshold integer Circuit breaker config circuitCooldownSeconds integer Circuit breaker config
POST /webhook-endpoints/{endpointId}/rotate-secret
Rotates the signing secret with optional grace period during which both old and new secrets are valid.
Field Type Default Description gracePeriodSeconds integer 3600 Grace period (max: 86400)
{
"secret" : "whsec_newkey123..." ,
"previousSecretExpiresAt" : "2024-01-20T16:00:00Z" ,
"secretVersion" : 2
}
POST /webhook-endpoints/{endpointId}/reset-circuit
Manually reset a circuit breaker to the closed state.
{
"success" : true ,
"circuitState" : "closed"
}
DELETE /webhook-endpoints/{endpointId}
Note: This cascades to delete all subscriptions for this endpoint.
GET /webhook-subscriptions
Parameter Type Default Description endpointId string - Filter by endpoint eventTypeId string - Filter by event type applicationId string - Filter by application isEnabled boolean - Filter by enabled status limit integer 50 Max results (1-100) cursor string - Pagination cursor
{
"data" : [
{
"id" : "wh_sub_xxx" ,
"endpointId" : "wh_ep_yyy" ,
"eventTypeId" : "evt_type_zzz" ,
"filterExpression" : null ,
"labelFilters" : { "region" : "us-west" },
"labelFilterMode" : "all" ,
"transformId" : null ,
"isEnabled" : true ,
"endpointUrl" : "https://api.customer.com/webhooks" ,
"eventTypeName" : "order.created" ,
"eventTypeDisplayName" : "Order Created" ,
"applicationId" : "wh_app_aaa" ,
"applicationName" : "Acme Corp" ,
"createdAt" : "2024-01-10T10:00:00Z"
}
],
"pagination" : {
"hasMore" : false ,
"nextCursor" : null
}
}
GET /webhook-subscriptions/{subscriptionId}
POST /webhook-subscriptions
Field Type Required Description endpointId string Yes Target endpoint eventTypeId string Yes Event type to subscribe to filterExpression string No Filter expression (max 1000 chars) labelFilters object No Label filter conditions labelFilterMode string No Filter mode: all or any transformId string No Transform to apply isEnabled boolean No Whether active (default: true)
{
"labelFilters" : {
"region" : "us-west" ,
"priority" : [ "high" , "urgent" ],
"environment" : "production"
},
"labelFilterMode" : "all"
}
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-subscriptions" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"endpointId": "wh_ep_xxx",
"eventTypeId": "evt_type_yyy",
"labelFilters": {
"region": "us-west"
},
"labelFilterMode": "all"
}'
{
"error" : "Duplicate subscription" ,
"message" : "This endpoint is already subscribed to this event type"
}
POST /webhook-subscriptions/bulk
Subscribe an endpoint to multiple event types at once.
Field Type Required Description endpointId string Yes Target endpoint eventTypeIds array Yes Event type IDs (max 100) labelFilters object No Label filters for all subscriptions labelFilterMode string No Filter mode: all or any
curl -X POST "https://api.hookbase.app/api/organizations/{orgId}/webhook-subscriptions/bulk" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"endpointId": "wh_ep_xxx",
"eventTypeIds": [
"evt_type_order_created",
"evt_type_order_updated",
"evt_type_order_cancelled"
]
}'
{
"created" : 3 ,
"skipped" : 0 ,
"subscriptions" : [ ... ]
}
PATCH /webhook-subscriptions/{subscriptionId}
Field Type Description filterExpression string Filter expression labelFilters object Label filter conditions labelFilterMode string Filter mode transformId string Transform ID isEnabled boolean Enable/disable
DELETE /webhook-subscriptions/{subscriptionId}
Parameter Type Default Description status string - Filter by status eventType string - Filter by event type name applicationId string - Filter by application endpointId string - Filter by endpoint limit integer 50 Max results (1-100) cursor string - Pagination cursor
Status Description pending Queued for delivery processing Currently being delivered success Successfully delivered failed Delivery failed (will retry) exhausted All retries exhausted dlq Moved to dead letter queue
{
"data" : [
{
"id" : "wh_msg_xxx" ,
"eventId" : "evt_yyy" ,
"eventType" : "order.created" ,
"applicationId" : "wh_app_zzz" ,
"endpointId" : "wh_ep_aaa" ,
"status" : "success" ,
"attempts" : 1 ,
"maxAttempts" : 5 ,
"lastResponseStatus" : 200 ,
"lastErrorMessage" : null ,
"createdAt" : "2024-01-20T10:00:00Z" ,
"completedAt" : "2024-01-20T10:00:01Z" ,
"endpointUrl" : "https://api.customer.com/webhooks" ,
"applicationName" : "Acme Corp"
}
],
"pagination" : {
"hasMore" : true ,
"nextCursor" : "2024-01-20T09:59:00Z"
}
}
GET /outbound-messages/{messageId}
GET /outbound-messages/{messageId}/attempts
{
"data" : [
{
"id" : "wh_att_xxx" ,
"messageId" : "wh_msg_yyy" ,
"attemptNumber" : 1 ,
"status" : "success" ,
"responseStatus" : 200 ,
"responseTimeMs" : 145 ,
"responseBody" : "{ \" received \" : true}" ,
"errorType" : null ,
"errorMessage" : null ,
"createdAt" : "2024-01-20T10:00:00Z" ,
"completedAt" : "2024-01-20T10:00:00Z"
}
]
}
POST /outbound-messages/{messageId}/replay
Create a new delivery attempt for a failed or exhausted message.
{
"data" : {
"originalMessageId" : "wh_msg_xxx" ,
"newMessageId" : "wh_msg_yyy" ,
"status" : "queued"
}
}
GET /outbound-messages/stats/summary
{
"data" : {
"pending" : 12 ,
"processing" : 3 ,
"success" : 15420 ,
"failed" : 45 ,
"exhausted" : 8 ,
"dlq" : 5 ,
"total" : 15493
}
}
GET /outbound-messages/export
Parameter Type Default Description format string json Export format (json/csv) type string events Export type (events/messages) startDate string - Start date (ISO 8601) endDate string - End date (ISO 8601) status string - Filter by status eventType string - Filter by event type applicationId string - Filter by application limit integer 10000 Max results (max: 50000)
GET /outbound-messages/dlq/messages
Parameter Type Default Description reason string - Filter by DLQ reason eventType string - Filter by event type applicationId string - Filter by application endpointId string - Filter by endpoint startDate string - Filter by dlqMovedAt start endDate string - Filter by dlqMovedAt end limit integer 50 Max results (1-100) cursor string - Pagination cursor
Reason Description max_retries_exceeded All retry attempts failed circuit_breaker_exhausted Circuit breaker open, retries exhausted endpoint_not_found Endpoint was deleted payload_not_found Payload missing from storage secret_decryption_failed Could not decrypt signing secret
{
"data" : [
{
"id" : "wh_msg_xxx" ,
"eventId" : "evt_yyy" ,
"eventType" : "order.created" ,
"status" : "dlq" ,
"attempts" : 5 ,
"maxAttempts" : 5 ,
"lastResponseStatus" : 500 ,
"lastErrorType" : "http_error" ,
"lastErrorMessage" : "HTTP 500: Internal Server Error" ,
"dlqReason" : "max_retries_exceeded" ,
"dlqMovedAt" : "2024-01-20T10:30:00Z" ,
"dlqRetryCount" : 0 ,
"dlqLastRetryAt" : null ,
"endpointUrl" : "https://api.customer.com/webhooks" ,
"applicationName" : "Acme Corp"
}
],
"pagination" : {
"hasMore" : false ,
"nextCursor" : null
}
}
GET /outbound-messages/dlq/stats
{
"data" : {
"total" : 25 ,
"byReason" : {
"max_retries_exceeded" : 20 ,
"circuit_breaker_exhausted" : 3 ,
"endpoint_not_found" : 2
},
"topFailingEndpoints" : [
{
"endpointId" : "wh_ep_xxx" ,
"endpointUrl" : "https://api.failing.com/webhooks" ,
"count" : 15
}
]
}
}
POST /outbound-messages/dlq/{messageId}/retry
{
"data" : {
"originalMessageId" : "wh_msg_xxx" ,
"newMessageId" : "wh_msg_yyy" ,
"status" : "queued"
}
}
POST /outbound-messages/dlq/retry-bulk
{
"messageIds" : [ "wh_msg_xxx" , "wh_msg_yyy" , "wh_msg_zzz" ]
}
Note: Maximum 100 messages per request.
{
"data" : {
"queued" : 3 ,
"skipped" : 0 ,
"messages" : [
{ "originalMessageId" : "wh_msg_xxx" , "newMessageId" : "wh_msg_aaa" },
{ "originalMessageId" : "wh_msg_yyy" , "newMessageId" : "wh_msg_bbb" },
{ "originalMessageId" : "wh_msg_zzz" , "newMessageId" : "wh_msg_ccc" }
]
}
}
DELETE /outbound-messages/dlq/{messageId}
Archives the message (marks as exhausted).
DELETE /outbound-messages/dlq/bulk
{
"messageIds" : [ "wh_msg_xxx" , "wh_msg_yyy" ]
}
Parameter Type Default Description timeRange string 24h Time range (1h/24h/7d/30d) applicationId string - Filter by application endpointId string - Filter by endpoint
{
"data" : {
"timeRange" : "24h" ,
"startTime" : "2024-01-19T10:00:00Z" ,
"summary" : {
"totalDeliveries" : 15420 ,
"successCount" : 15350 ,
"failedCount" : 70 ,
"pendingCount" : 12 ,
"processingCount" : 3 ,
"dlqCount" : 5 ,
"successRate" : 99.55
},
"latency" : {
"p50" : 120 ,
"p95" : 450 ,
"p99" : 890 ,
"avg" : 145
},
"topFailingEndpoints" : [
{
"endpointId" : "wh_ep_xxx" ,
"endpointUrl" : "https://api.slow.com/webhooks" ,
"circuitState" : "half_open" ,
"failureCount" : 25 ,
"totalMessages" : 500 ,
"totalSuccesses" : 475 ,
"totalFailures" : 25
}
],
"errorTypes" : [
{ "type" : "timeout" , "count" : 30 },
{ "type" : "http_error" , "count" : 25 },
{ "type" : "network" , "count" : 15 }
],
"dlqByReason" : {
"max_retries_exceeded" : 4 ,
"circuit_breaker_exhausted" : 1
},
"chartData" : [
{ "period" : "2024-01-19 10:00" , "success" : 450 , "failed" : 3 , "pending" : 0 },
{ "period" : "2024-01-19 11:00" , "success" : 520 , "failed" : 2 , "pending" : 0 }
]
}
}
GET /webhooks/analytics/endpoints/{endpointId}
Parameter Type Default Description timeRange string 24h Time range (1h/24h/7d/30d)
{
"data" : {
"endpoint" : {
"id" : "wh_ep_xxx" ,
"url" : "https://api.customer.com/webhooks" ,
"circuitState" : "closed" ,
"circuitFailureCount" : 0 ,
"totalMessages" : 1542 ,
"totalSuccesses" : 1520 ,
"totalFailures" : 22 ,
"avgResponseTimeMs" : 145 ,
"lastSuccessAt" : "2024-01-20T15:30:00Z" ,
"lastFailureAt" : "2024-01-18T10:00:00Z"
},
"stats" : {
"success" : 320 ,
"failed" : 5 ,
"pending" : 2 ,
"avgResponseTimeMs" : 142
},
"recentAttempts" : [
{
"id" : "wh_att_xxx" ,
"messageId" : "wh_msg_yyy" ,
"attemptNumber" : 1 ,
"status" : "success" ,
"responseStatus" : 200 ,
"responseTimeMs" : 125 ,
"createdAt" : "2024-01-20T15:30:00Z"
}
]
}
}
All error responses follow this format:
{
"error" : "Error type" ,
"message" : "Detailed error message" ,
"details" : {
"field" : [ "Validation error message" ]
}
}
Status Error Description 400 Invalid input Request validation failed 401 Unauthorized Missing or invalid authentication 403 Forbidden Insufficient permissions or feature not enabled 404 Not found Resource does not exist 409 Conflict Duplicate resource 413 Payload too large Request body exceeds limit 429 Rate limited Too many requests 500 Internal error Server error
Endpoint Limit POST /send-event Plan-based (100-10000 events/min) Other endpoints 1000 requests/minute
Rate limit headers are included in responses:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1705750800