Webhook API Reference
This document provides a complete reference for the Hookbase webhook subscription API endpoints.
Authentication
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" ...Base URL
https://api.hookbase.app/api/organizations/{orgId}Replace {orgId} with your organization ID.
Send Event
Send an event to all subscribed endpoints.
Endpoint
POST /send-eventRequest Body
| 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 |
Example Request
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"
}
}'Response (201 Created)
{
"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"}
]
}
}Error Responses
| 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 |
Event Types
List Event Types
GET /event-typesQuery Parameters
| 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 |
Example Request
curl "https://api.hookbase.app/api/organizations/{orgId}/event-types?category=orders&limit=20" \
-H "Authorization: Bearer {token}"Response (200 OK)
{
"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 Type
GET /event-types/{eventTypeId}Response (200 OK)
{
"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"
}
}Create Event Type
POST /event-typesRequest Body
| 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) |
Example Request
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}"
}'Response (201 Created)
{
"data": {
"id": "evt_type_xxx",
"name": "payment.succeeded",
"displayName": "Payment Succeeded",
"isEnabled": true,
"createdAt": "2024-01-20T10:00:00Z"
}
}Update Event Type
PATCH /event-types/{eventTypeId}Request Body
| 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 |
Example Request
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 Type
DELETE /event-types/{eventTypeId}Note: This cascades to delete all subscriptions for this event type.
Response (200 OK)
{
"success": true
}Webhook Applications
List Applications
GET /webhook-applicationsQuery Parameters
| 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) |
Response (200 OK)
{
"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 Application
GET /webhook-applications/{applicationId}Get Application by External ID
GET /webhook-applications/by-external-id/{externalId}Useful for looking up applications using your internal customer ID.
Create Application
POST /webhook-applicationsRequest Body
| 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) |
Example Request
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]"
}
}'Upsert Application
PUT /webhook-applications/upsertCreate or update an application by external ID. Useful for syncing from your customer database.
Request Body
| 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 |
Response (200 OK or 201 Created)
{
"data": {...},
"created": true
}Update Application
PATCH /webhook-applications/{applicationId}Request Body
| 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 Application
DELETE /webhook-applications/{applicationId}Note: This cascades to delete all endpoints and subscriptions.
Webhook Endpoints
List Endpoints
GET /webhook-endpointsQuery Parameters
| 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 |
Response (200 OK)
{
"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 Endpoint
GET /webhook-endpoints/{endpointId}Create Endpoint
POST /webhook-endpointsRequest Body
| 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 Format
{
"headers": [
{"name": "X-Custom-Header", "value": "my-value"},
{"name": "Authorization", "value": "Bearer token123"}
]
}Example Request
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
}'Response (201 Created)
{
"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."
}Update Endpoint
PATCH /webhook-endpoints/{endpointId}Request Body
| 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 |
Rotate Endpoint Secret
POST /webhook-endpoints/{endpointId}/rotate-secretRotates the signing secret with optional grace period during which both old and new secrets are valid.
Request Body
| Field | Type | Default | Description |
|---|---|---|---|
gracePeriodSeconds | integer | 3600 | Grace period (max: 86400) |
Response (200 OK)
{
"secret": "whsec_newkey123...",
"previousSecretExpiresAt": "2024-01-20T16:00:00Z",
"secretVersion": 2
}Reset Circuit Breaker
POST /webhook-endpoints/{endpointId}/reset-circuitManually reset a circuit breaker to the closed state.
Response (200 OK)
{
"success": true,
"circuitState": "closed"
}Delete Endpoint
DELETE /webhook-endpoints/{endpointId}Note: This cascades to delete all subscriptions for this endpoint.
Webhook Subscriptions
List Subscriptions
GET /webhook-subscriptionsQuery Parameters
| 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 |
Response (200 OK)
{
"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 Subscription
GET /webhook-subscriptions/{subscriptionId}Create Subscription
POST /webhook-subscriptionsRequest Body
| 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) |
Label Filters Format
{
"labelFilters": {
"region": "us-west",
"priority": ["high", "urgent"],
"environment": "production"
},
"labelFilterMode": "all"
}Example Request
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 Response (409 Conflict)
{
"error": "Duplicate subscription",
"message": "This endpoint is already subscribed to this event type"
}Bulk Create Subscriptions
POST /webhook-subscriptions/bulkSubscribe an endpoint to multiple event types at once.
Request Body
| 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 |
Example Request
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"
]
}'Response (201 Created)
{
"created": 3,
"skipped": 0,
"subscriptions": [...]
}Update Subscription
PATCH /webhook-subscriptions/{subscriptionId}Request Body
| 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 Subscription
DELETE /webhook-subscriptions/{subscriptionId}Outbound Messages
List Messages
GET /outbound-messagesQuery Parameters
| 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 Values
| 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 |
Response (200 OK)
{
"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 Message Details
GET /outbound-messages/{messageId}Get Message Attempts
GET /outbound-messages/{messageId}/attemptsResponse (200 OK)
{
"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"
}
]
}Replay Message
POST /outbound-messages/{messageId}/replayCreate a new delivery attempt for a failed or exhausted message.
Response (201 Created)
{
"data": {
"originalMessageId": "wh_msg_xxx",
"newMessageId": "wh_msg_yyy",
"status": "queued"
}
}Get Message Statistics
GET /outbound-messages/stats/summaryResponse (200 OK)
{
"data": {
"pending": 12,
"processing": 3,
"success": 15420,
"failed": 45,
"exhausted": 8,
"dlq": 5,
"total": 15493
}
}Export Messages
GET /outbound-messages/exportQuery Parameters
| 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) |
Dead Letter Queue (DLQ)
List DLQ Messages
GET /outbound-messages/dlq/messagesQuery Parameters
| 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 |
DLQ Reasons
| 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 |
Response (200 OK)
{
"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 DLQ Statistics
GET /outbound-messages/dlq/statsResponse (200 OK)
{
"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
}
]
}
}Retry DLQ Message
POST /outbound-messages/dlq/{messageId}/retryResponse (201 Created)
{
"data": {
"originalMessageId": "wh_msg_xxx",
"newMessageId": "wh_msg_yyy",
"status": "queued"
}
}Bulk Retry DLQ Messages
POST /outbound-messages/dlq/retry-bulkRequest Body
{
"messageIds": ["wh_msg_xxx", "wh_msg_yyy", "wh_msg_zzz"]
}Note: Maximum 100 messages per request.
Response (201 Created)
{
"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 DLQ Message
DELETE /outbound-messages/dlq/{messageId}Archives the message (marks as exhausted).
Bulk Delete DLQ Messages
DELETE /outbound-messages/dlq/bulkRequest Body
{
"messageIds": ["wh_msg_xxx", "wh_msg_yyy"]
}Analytics
Get Delivery Analytics
GET /webhooks/analyticsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
timeRange | string | 24h | Time range (1h/24h/7d/30d) |
applicationId | string | - | Filter by application |
endpointId | string | - | Filter by endpoint |
Response (200 OK)
{
"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 Endpoint Analytics
GET /webhooks/analytics/endpoints/{endpointId}Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
timeRange | string | 24h | Time range (1h/24h/7d/30d) |
Response (200 OK)
{
"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"
}
]
}
}Error Responses
All error responses follow this format:
{
"error": "Error type",
"message": "Detailed error message",
"details": {
"field": ["Validation error message"]
}
}Common Error Codes
| 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 |
Rate Limits
| 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