Webhook Endpoints
Webhook endpoints receive real-time HTTP notifications about events in your account. Instead of polling the API for changes, configure a URL and EPD will push events to you as they happen.
Quick Start
- Create an endpoint with your URL and desired events
- Store the
signing_secretreturned on creation (shown only once) - Verify signatures on incoming webhooks using HMAC-SHA256
- Respond with
2xxwithin 30 seconds to acknowledge receipt
Security
Always verify the EPD-Signature header before processing webhook payloads. See the Webhooks guide section for signature verification details.
/webhook_endpoints Create a webhook endpoint
Creates a new webhook endpoint to receive real-time event notifications. The signing_secret is returned only once in this response: store it securely in your environment variables.
Event Patterns
Subscribe to specific events or use wildcards:
| Pattern | Matches |
|---|---|
* |
All events |
order.* |
All order events (created, succeeded, failed, refunded, etc.) |
subscription.* |
All subscription events |
customer.created |
Only customer creation events |
After Creation
- Store the
signing_secret: it's shown only once and cannot be retrieved later - Verify signatures on incoming webhooks using HMAC-SHA256
- Return
2xxwithin 30 seconds to acknowledge receipt - Test connectivity with
POST /v1/webhook_endpoints/:id/test
Security: Your endpoint URL must use HTTPS. HTTP URLs are rejected.
Header parameters
string"2026-02-11"string (uuid)"550e8400-e29b-41d4-a716-446655440000"Request body required
string (uri)"https://example.com/webhooks"string"Production webhook endpoint"array[string]["order.*","subscription.created","customer.*"]string"2026-02-10"Code samples
curl -X POST https://api.epd.com/v1/webhook_endpoints \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "Content-Type: application/json" \
-H "EPD-Version: 2026-02-11" \
-H "X-EPD-Idempotency-Key: $(uuidgen)" \
-d '{
"url": "https://example.com/webhooks",
"description": "Production webhook endpoint",
"enabled_events": ["order.*", "subscription.*", "customer.*"]
}'
# IMPORTANT: Save the signing_secret from the response! const response = await fetch('https://api.epd.com/v1/webhook_endpoints', {
method: 'POST',
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'Content-Type': 'application/json',
'EPD-Version': '2026-02-11',
'X-EPD-Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
url: 'https://example.com/webhooks',
description: 'Production webhook endpoint',
enabled_events: ['order.*', 'subscription.*', 'customer.*'],
}),
});
const endpoint = await response.json();
// IMPORTANT: Store this securely; it's shown only once!
console.log(endpoint.signing_secret); // whsec_xxxxxxxxxxxxxxxxxxxx import uuid
import requests
response = requests.post(
'https://api.epd.com/v1/webhook_endpoints',
headers={
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
'X-EPD-Idempotency-Key': str(uuid.uuid4()),
},
json={
'url': 'https://example.com/webhooks',
'description': 'Production webhook endpoint',
'enabled_events': ['order.*', 'subscription.*', 'customer.*'],
}
)
endpoint = response.json()
# IMPORTANT: Store this securely; it's shown only once!
print(endpoint['signing_secret']) # whsec_xxxxxxxxxxxxxxxxxxxx Responses
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"string (uri)"https://example.com/webhooks"string"Production webhook endpoint"array[string]["order.*","subscription.created"]enumenableddisabled"enabled"string"whsec_xxxxxxxxxxxxxxxxxxxx"booleanfalsestring (date-time)string (date-time)"2024-01-15T10:30:00.000Z"string (date-time)"2024-01-15T10:30:00.000Z"string"2026-02-10"string (date-time)booleanfalsestringobjectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints List all webhook endpoints
Returns a paginated list. signing_secret is never returned in list responses.
Query parameters
integer10string"550e8400-e29b-41d4-a716-446655440000"string"550e8400-e29b-41d4-a716-446655440001"Header parameters
string"2026-02-11"Responses
array[WebhookEndpoint]any"/v1/webhook_endpoints"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id} Retrieve a webhook endpoint
signing_secret is never returned.
Path parameters
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"Header parameters
string"2026-02-11"Responses
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"string (uri)"https://example.com/webhooks"string"Production webhook endpoint"array[string]["order.*","subscription.created"]enumenableddisabled"enabled"string"whsec_xxxxxxxxxxxxxxxxxxxx"booleanfalsestring (date-time)string (date-time)"2024-01-15T10:30:00.000Z"string (date-time)"2024-01-15T10:30:00.000Z"string"2026-02-10"string (date-time)booleanfalsestringobjectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id} Update a webhook endpoint
signing_secret is never returned on update.
Path parameters
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"Header parameters
string"2026-02-11"string (uuid)"550e8400-e29b-41d4-a716-446655440000"Request body required
string (uri)"https://example.com/webhooks/v2"string"Updated production webhook endpoint"array[string]["order.*","customer.*"]enumenableddisabled"enabled"string"2026-02-10"Responses
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"string (uri)"https://example.com/webhooks"string"Production webhook endpoint"array[string]["order.*","subscription.created"]enumenableddisabled"enabled"string"whsec_xxxxxxxxxxxxxxxxxxxx"booleanfalsestring (date-time)string (date-time)"2024-01-15T10:30:00.000Z"string (date-time)"2024-01-15T10:30:00.000Z"string"2026-02-10"string (date-time)booleanfalsestringobjectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id} Delete a webhook endpoint
Path parameters
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"Header parameters
string"2026-02-11"Responses
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"truestring"Webhook endpoint successfully deleted."objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id}/rotate_secret Rotate signing secret
Generates a new signing secret for the webhook endpoint. During the grace period, both the old and new secrets are valid, giving you time to update your verification code without dropping events.
Rotation Flow
- Call this endpoint → receive
new_signing_secret - Deploy your updated verification code (accept both old and new secrets)
- After the grace period expires, only the new secret works
Grace Period
| Value | Use Case |
|---|---|
1 hour |
Quick rotation, single-server deployments |
24 hours (default) |
Standard rotation, multi-server deployments |
72 hours |
Large deployments with rolling updates |
Security: Rotate secrets periodically or immediately if you suspect a secret has been compromised.
Path parameters
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"Header parameters
string"2026-02-11"string (uuid)"550e8400-e29b-41d4-a716-446655440000"Request body
integer24Code samples
curl -X POST https://api.epd.com/v1/webhook_endpoints/6ba7b817-9dad-11d1-80b4-00c04fd430c8/rotate_secret \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "Content-Type: application/json" \
-H "EPD-Version: 2026-02-11" \
-H "X-EPD-Idempotency-Key: $(uuidgen)" \
-d '{ "grace_period_hours": 24 }' const response = await fetch(
'https://api.epd.com/v1/webhook_endpoints/6ba7b817-9dad-11d1-80b4-00c04fd430c8/rotate_secret',
{
method: 'POST',
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'Content-Type': 'application/json',
'EPD-Version': '2026-02-11',
'X-EPD-Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({ grace_period_hours: 24 }),
}
);
const result = await response.json();
// Deploy this new secret to your webhook handler
console.log(result.new_signing_secret);
console.log(result.previous_secret_valid_until); // Unix timestamp Responses
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"string"whsec_new_xxxxxxxxxxxx"string (date-time)"2024-01-16T10:30:00.000Z"string"New secret active. Previous secret valid for 24 hours."objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id}/test Send a test event
Sends a test webhook event to the endpoint to verify connectivity.
Path parameters
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"Header parameters
string"2026-02-11"Request body
string"order.succeeded"string"2026-02-10"Responses
string"wht_123"string"6ba7b817-9dad-11d1-80b4-00c04fd430d0"enumsuccessfailed"success"integer200integer150stringstring (date-time)"2024-01-15T10:30:00.000Z"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id}/events List webhook events
Returns events sent to a specific webhook endpoint.
Path parameters
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"Query parameters
integer10string"550e8400-e29b-41d4-a716-446655440000"string"delivered"Header parameters
string"2026-02-11"Responses
array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id}/delivery_logs List delivery logs
Returns delivery attempt logs for a specific webhook endpoint.
Path parameters
string"6ba7b817-9dad-11d1-80b4-00c04fd430c8"Query parameters
integer10string"550e8400-e29b-41d4-a716-446655440000"Header parameters
string"2026-02-11"Responses
array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/webhook_endpoints/{id}/upgrade_version Upgrade endpoint version
Path parameters
stringRequest body required
string"2026-02-10"booleanResponses
stringstringstringintegerstring/webhook_endpoints/{id}/downgrade_version Downgrade endpoint version
Path parameters
stringRequest body required
string"2026-02-10"booleanResponses
stringstringstringintegerstring/webhook_endpoints/{id}/events/{eventId}/replay Replay webhook event
Path parameters
stringstringRequest body required
stringbooleanResponses
stringstringstringstringstringstring