Skip to content

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:

bash
# 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-event

Request Body

FieldTypeRequiredDescription
eventTypestringYesEvent type name (e.g., order.created)
payloadanyYesEvent payload (JSON-serializable)
applicationIdstringNoTarget a specific application
endpointIdstringNoTarget a specific endpoint
idempotencyKeystringNoUnique key to prevent duplicate processing
labelsobjectNoKey-value labels for filtering
metadataobjectNoAdditional metadata stored with the event

Example Request

bash
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)

json
{
  "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

StatusErrorDescription
400Invalid inputRequest body validation failed
404Event type not foundNo enabled event type with this name
413Payload too largePayload exceeds plan limit
415Invalid Content-TypeContent-Type must be application/json
429Rate limit exceededToo many events sent
429Monthly limit exceededMonthly message quota exceeded

Event Types

List Event Types

GET /event-types

Query Parameters

ParameterTypeDefaultDescription
categorystring-Filter by category
isEnabledboolean-Filter by enabled status
searchstring-Search by name
limitinteger50Max results (1-100)
cursorstring-Pagination cursor

Example Request

bash
curl "https://api.hookbase.app/api/organizations/{orgId}/event-types?category=orders&limit=20" \
  -H "Authorization: Bearer {token}"

Response (200 OK)

json
{
  "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)

json
{
  "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-types

Request Body

FieldTypeRequiredDescription
namestringYesUnique name (lowercase, dot-separated)
displayNamestringNoHuman-readable name
descriptionstringNoDescription (max 1000 chars)
categorystringNoCategory for grouping
schemastringNoJSON Schema for validation
examplePayloadstringNoExample payload (JSON string)
documentationUrlstringNoLink to documentation
isEnabledbooleanNoWhether active (default: true)

Example Request

bash
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)

json
{
  "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

FieldTypeDescription
displayNamestringHuman-readable name
descriptionstringDescription
categorystringCategory
schemastringJSON Schema (increments schemaVersion)
examplePayloadstringExample payload
documentationUrlstringDocumentation URL
isEnabledbooleanEnable/disable
isDeprecatedbooleanMark as deprecated
deprecatedMessagestringDeprecation notice

Example Request

bash
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)

json
{
  "success": true
}

Webhook Applications

List Applications

GET /webhook-applications

Query Parameters

ParameterTypeDefaultDescription
searchstring-Search by name
isDisabledboolean-Filter by disabled status
limitinteger50Max results (1-100)
cursorstring-Pagination cursor
orderBystringcreated_atSort field
orderstringdescSort direction (asc/desc)

Response (200 OK)

json
{
  "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-applications

Request Body

FieldTypeRequiredDescription
namestringYesApplication name
externalIdstringNoYour internal customer ID
metadataobjectNoCustom metadata
rateLimitPerSecondintegerNoRate limit (default: 100)
rateLimitPerMinuteintegerNoRate limit (default: 1000)
rateLimitPerHourintegerNoRate limit (default: 10000)

Example Request

bash
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/upsert

Create or update an application by external ID. Useful for syncing from your customer database.

Request Body

FieldTypeRequiredDescription
externalIdstringYesYour internal customer ID
namestringYesApplication name
metadataobjectNoCustom metadata
rateLimitPerSecondintegerNoRate limit
rateLimitPerMinuteintegerNoRate limit
rateLimitPerHourintegerNoRate limit

Response (200 OK or 201 Created)

json
{
  "data": {...},
  "created": true
}

Update Application

PATCH /webhook-applications/{applicationId}

Request Body

FieldTypeDescription
namestringApplication name
metadataobjectCustom metadata
rateLimitPerSecondintegerRate limit
rateLimitPerMinuteintegerRate limit
rateLimitPerHourintegerRate limit
isDisabledbooleanDisable/enable
disabledReasonstringReason for disabling

Delete Application

DELETE /webhook-applications/{applicationId}

Note: This cascades to delete all endpoints and subscriptions.


Webhook Endpoints

List Endpoints

GET /webhook-endpoints

Query Parameters

ParameterTypeDefaultDescription
applicationIdstring-Filter by application
isDisabledboolean-Filter by disabled status
circuitStatestring-Filter by circuit state (closed/open/half_open)
limitinteger50Max results (1-100)
cursorstring-Pagination cursor

Response (200 OK)

json
{
  "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-endpoints

Request Body

FieldTypeRequiredDescription
applicationIdstringYesParent application ID
urlstringYesHTTPS endpoint URL
descriptionstringNoDescription (max 500 chars)
headersarrayNoCustom headers to include
timeoutSecondsintegerNoRequest timeout (default: 30, max: 120)
rateLimitPerSecondintegerNoEndpoint rate limit (0 = unlimited)
circuitFailureThresholdintegerNoFailures to open circuit (default: 5)
circuitSuccessThresholdintegerNoSuccesses to close circuit (default: 2)
circuitCooldownSecondsintegerNoCooldown period (default: 60)

Headers Format

json
{
  "headers": [
    {"name": "X-Custom-Header", "value": "my-value"},
    {"name": "Authorization", "value": "Bearer token123"}
  ]
}

Example Request

bash
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)

json
{
  "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

FieldTypeDescription
urlstringEndpoint URL
descriptionstringDescription
headersarrayCustom headers
timeoutSecondsintegerRequest timeout
isDisabledbooleanDisable/enable
disabledReasonstringReason for disabling
rateLimitPerSecondintegerRate limit
circuitFailureThresholdintegerCircuit breaker config
circuitSuccessThresholdintegerCircuit breaker config
circuitCooldownSecondsintegerCircuit breaker config

Rotate Endpoint Secret

POST /webhook-endpoints/{endpointId}/rotate-secret

Rotates the signing secret with optional grace period during which both old and new secrets are valid.

Request Body

FieldTypeDefaultDescription
gracePeriodSecondsinteger3600Grace period (max: 86400)

Response (200 OK)

json
{
  "secret": "whsec_newkey123...",
  "previousSecretExpiresAt": "2024-01-20T16:00:00Z",
  "secretVersion": 2
}

Reset Circuit Breaker

POST /webhook-endpoints/{endpointId}/reset-circuit

Manually reset a circuit breaker to the closed state.

Response (200 OK)

json
{
  "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-subscriptions

Query Parameters

ParameterTypeDefaultDescription
endpointIdstring-Filter by endpoint
eventTypeIdstring-Filter by event type
applicationIdstring-Filter by application
isEnabledboolean-Filter by enabled status
limitinteger50Max results (1-100)
cursorstring-Pagination cursor

Response (200 OK)

json
{
  "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-subscriptions

Request Body

FieldTypeRequiredDescription
endpointIdstringYesTarget endpoint
eventTypeIdstringYesEvent type to subscribe to
filterExpressionstringNoFilter expression (max 1000 chars)
labelFiltersobjectNoLabel filter conditions
labelFilterModestringNoFilter mode: all or any
transformIdstringNoTransform to apply
isEnabledbooleanNoWhether active (default: true)

Label Filters Format

json
{
  "labelFilters": {
    "region": "us-west",
    "priority": ["high", "urgent"],
    "environment": "production"
  },
  "labelFilterMode": "all"
}

Example Request

bash
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)

json
{
  "error": "Duplicate subscription",
  "message": "This endpoint is already subscribed to this event type"
}

Bulk Create Subscriptions

POST /webhook-subscriptions/bulk

Subscribe an endpoint to multiple event types at once.

Request Body

FieldTypeRequiredDescription
endpointIdstringYesTarget endpoint
eventTypeIdsarrayYesEvent type IDs (max 100)
labelFiltersobjectNoLabel filters for all subscriptions
labelFilterModestringNoFilter mode: all or any

Example Request

bash
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)

json
{
  "created": 3,
  "skipped": 0,
  "subscriptions": [...]
}

Update Subscription

PATCH /webhook-subscriptions/{subscriptionId}

Request Body

FieldTypeDescription
filterExpressionstringFilter expression
labelFiltersobjectLabel filter conditions
labelFilterModestringFilter mode
transformIdstringTransform ID
isEnabledbooleanEnable/disable

Delete Subscription

DELETE /webhook-subscriptions/{subscriptionId}

Outbound Messages

List Messages

GET /outbound-messages

Query Parameters

ParameterTypeDefaultDescription
statusstring-Filter by status
eventTypestring-Filter by event type name
applicationIdstring-Filter by application
endpointIdstring-Filter by endpoint
limitinteger50Max results (1-100)
cursorstring-Pagination cursor

Status Values

StatusDescription
pendingQueued for delivery
processingCurrently being delivered
successSuccessfully delivered
failedDelivery failed (will retry)
exhaustedAll retries exhausted
dlqMoved to dead letter queue

Response (200 OK)

json
{
  "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}/attempts

Response (200 OK)

json
{
  "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}/replay

Create a new delivery attempt for a failed or exhausted message.

Response (201 Created)

json
{
  "data": {
    "originalMessageId": "wh_msg_xxx",
    "newMessageId": "wh_msg_yyy",
    "status": "queued"
  }
}

Get Message Statistics

GET /outbound-messages/stats/summary

Response (200 OK)

json
{
  "data": {
    "pending": 12,
    "processing": 3,
    "success": 15420,
    "failed": 45,
    "exhausted": 8,
    "dlq": 5,
    "total": 15493
  }
}

Export Messages

GET /outbound-messages/export

Query Parameters

ParameterTypeDefaultDescription
formatstringjsonExport format (json/csv)
typestringeventsExport type (events/messages)
startDatestring-Start date (ISO 8601)
endDatestring-End date (ISO 8601)
statusstring-Filter by status
eventTypestring-Filter by event type
applicationIdstring-Filter by application
limitinteger10000Max results (max: 50000)

Dead Letter Queue (DLQ)

List DLQ Messages

GET /outbound-messages/dlq/messages

Query Parameters

ParameterTypeDefaultDescription
reasonstring-Filter by DLQ reason
eventTypestring-Filter by event type
applicationIdstring-Filter by application
endpointIdstring-Filter by endpoint
startDatestring-Filter by dlqMovedAt start
endDatestring-Filter by dlqMovedAt end
limitinteger50Max results (1-100)
cursorstring-Pagination cursor

DLQ Reasons

ReasonDescription
max_retries_exceededAll retry attempts failed
circuit_breaker_exhaustedCircuit breaker open, retries exhausted
endpoint_not_foundEndpoint was deleted
payload_not_foundPayload missing from storage
secret_decryption_failedCould not decrypt signing secret

Response (200 OK)

json
{
  "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/stats

Response (200 OK)

json
{
  "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}/retry

Response (201 Created)

json
{
  "data": {
    "originalMessageId": "wh_msg_xxx",
    "newMessageId": "wh_msg_yyy",
    "status": "queued"
  }
}

Bulk Retry DLQ Messages

POST /outbound-messages/dlq/retry-bulk

Request Body

json
{
  "messageIds": ["wh_msg_xxx", "wh_msg_yyy", "wh_msg_zzz"]
}

Note: Maximum 100 messages per request.

Response (201 Created)

json
{
  "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/bulk

Request Body

json
{
  "messageIds": ["wh_msg_xxx", "wh_msg_yyy"]
}

Analytics

Get Delivery Analytics

GET /webhooks/analytics

Query Parameters

ParameterTypeDefaultDescription
timeRangestring24hTime range (1h/24h/7d/30d)
applicationIdstring-Filter by application
endpointIdstring-Filter by endpoint

Response (200 OK)

json
{
  "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

ParameterTypeDefaultDescription
timeRangestring24hTime range (1h/24h/7d/30d)

Response (200 OK)

json
{
  "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:

json
{
  "error": "Error type",
  "message": "Detailed error message",
  "details": {
    "field": ["Validation error message"]
  }
}

Common Error Codes

StatusErrorDescription
400Invalid inputRequest validation failed
401UnauthorizedMissing or invalid authentication
403ForbiddenInsufficient permissions or feature not enabled
404Not foundResource does not exist
409ConflictDuplicate resource
413Payload too largeRequest body exceeds limit
429Rate limitedToo many requests
500Internal errorServer error

Rate Limits

EndpointLimit
POST /send-eventPlan-based (100-10000 events/min)
Other endpoints1000 requests/minute

Rate limit headers are included in responses:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1705750800

Released under the MIT License.