Skip to main content
GET
Webhook Delivery Logs

Webhook Delivery Logs

Every webhook dispatch — merchant-registered webhooks and app-scoped webhooks — is persisted as a delivery log. The platform exposes three views over these logs:
  1. Merchant-scoped — store owner/staff inspects deliveries across all apps installed on their store.
  2. Developer-scoped (per-app) — app owner inspects every delivery to their app, across every install.
  3. Manual retry — kick off a fresh delivery attempt that respects the original secret and exponential-backoff retry queue.
All endpoints require merchant (or staff-admin) JWT auth. There is no public app-scoped endpoint — apps can subscribe to delivery-failure notifications, but cannot read merchant logs over the OAuth API.

Delivery log fields

FieldTypeNotes
deliveryIdUUIDUnique id. Surfaced as :deliveryId in URLs.
webhookIdstringThe app or merchant webhook this delivery belongs to.
webhookType'app' | 'merchant'Whether the webhook is app-registered or merchant-registered.
storeIdUUIDThe merchant who owns this delivery.
topicstringe.g. orders/create, customers/redact.
callbackUrlstringURL we POST to.
payloadobjectExact body sent (without HMAC; HMAC is in headers).
statusenumPENDING, RETRYING, SUCCESS, FAILED.
attemptsintegerNumber of delivery attempts so far (0-3).
lastAttemptAttimestampWhen the most recent send happened.
nextRetryAttimestamp | nullWhen the next retry is scheduled. null once SUCCESS or terminal FAILED.
responseCodeinteger | nullHTTP status from the last attempt.
responseBodytext | nullFirst few KB of the response body (truncated).
errorMessagetext | nullNetwork error message (timeout, DNS, TLS) if no HTTP response.

Retry Schedule

Failed dispatches retry 3 times with exponential backoff:
AttemptDelay after previousCumulative time
1 (initial)0
21 minute1m
35 minutes6m
4 (final)15 minutes21m
After the fourth failed attempt, status is set to FAILED and nextRetryAt is cleared. The delivery can still be retried manually via the /retry endpoint below — this re-arms the row but starts the attempt counter fresh.

Merchant Endpoints

GET /apps/store/webhook-logs

List webhook deliveries for the caller’s store.
page
integer
default:"1"
Page number.
limit
integer
default:"20"
Items per page.
status
string
Filter: PENDING, RETRYING, SUCCESS, FAILED.
topic
string
Filter by webhook topic (e.g. orders/create).
Response:

GET /apps/store/webhook-logs/:deliveryId

Return the full record including payload and responseBody.
404 Delivery log not found when no row matches (deliveryId, storeId).

POST /apps/store/webhook-logs/:deliveryId/retry

Manually trigger a fresh send. The retry uses the original secret, callbackUrl, and payload from the row — only attempts is reset.

Developer Endpoints (per-app, all stores)

These views require ownership of the app — the platform verifies it first and returns 403 Forbidden if the JWT’s storeId is not the app’s developerId.

GET /apps/developer/:appId/webhook-deliveries

Same query parameters as the merchant endpoint, but scoped to one app across all of its installations.

GET /apps/developer/:appId/webhook-deliveries/stats

Aggregate counters (last 24h / 7d / 30d) plus per-topic failure rates — useful for the developer dashboard’s health page.

GET /apps/developer/:appId/webhook-deliveries/:deliveryId

Same as the merchant single-delivery view but scoped to one app.

POST /apps/developer/:appId/webhook-deliveries/:deliveryId/retry

Manually retry. Same semantics as the merchant retry, scoped to one app.

Error Codes

HTTPErrorWhen
401(auth guard)Missing/invalid merchant JWT.
403ForbiddenDeveloper endpoints — caller doesn’t own :appId.
404Delivery log not found:deliveryId doesn’t exist or belongs to another store/app.
500(generic)DB read error.

Operational Notes

  • The signing secret is captured with each delivery so that retries (both automatic and manual) can re-sign the body. Rotating clientSecret does not invalidate pending retries — they continue with the secret as of first dispatch.
  • responseBody is truncated to the first ~64KB. Use it for debugging; do not rely on it for full audit retention.