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