Designing API Webhook Delivery Receipts: The Audit Trail Customers Build Reports From
Customers do not just want webhooks to be delivered. They want to prove to themselves and to their auditors that the webhooks were delivered and processed. The delivery receipt is the load-bearing object that makes the audit story work.
The standard webhook delivery story stops at the response code. The sender retries on non-2xx, gives up after some budget, and writes the result to internal logs. From the customer's perspective, the operational view of "did my webhook actually get to me" is a black box: they see what they received in their handler, and they trust that what they did not receive was either never sent or was lost in transit.
This works until a customer needs to answer the question "what did we receive from you in March, and what did we do with it?" The question shows up at audit time, at incident retrospective time, when a customer's downstream system has been silently missing events, and when reconciling reported revenue or activity against an external system. The standard logging-only answer is not enough because it depends on the customer having logged everything correctly, which they did not.
The delivery receipt is the answer to this class of question. It is a customer-facing record of every delivery attempt, with enough detail to support both the customer's operational debugging and their compliance reporting. Done well, it converts a class of webhook-related support tickets into self-service queries and gives customers the information they need to trust the integration.
What a delivery receipt should contain
The minimum useful record has nine fields: a stable delivery_id that uniquely identifies this delivery attempt, the event_id the delivery represents, the subscription_id identifying which endpoint received the delivery, the timestamp when delivery was attempted, the destination URL, the HTTP method, the response status code, the response body (truncated), and the attempt number for this event-subscription pair.
Optional but commonly useful fields include the request headers sent (signature, timestamp, event metadata), the response headers received, the response duration in milliseconds, the IP address resolved for the destination, and any error details if the attempt failed before a response was received. The pattern is that each field answers a question customers ask when something goes wrong.
The retention period for delivery receipts should match or exceed the retention for the underlying events. We default to 30 days hot retention with longer cold-tier archives for customers on plans that include audit features. The hot retention covers most operational debugging; the archive retention covers the compliance questions that appear weeks or months after the fact.
What customers actually do with receipts
The four canonical customer workflows are debugging a specific event not appearing in downstream system, generating monthly reports for compliance, monitoring delivery success rate as part of integration health, and reconciling activity counts against external data sources.
Each workflow has different access pattern requirements. Debugging is point-lookup by event ID or delivery ID. Reports are range scans over a date window filtered by subscription and status. Monitoring is aggregate queries over the last hour or day. Reconciliation is range scans potentially over months with secondary filters.
The schema needs to support all four with indexes that match. The minimum useful index set is composite indexes on (subscription_id, attempted_at), (event_id), and (delivery_id) as primary key. Adding (subscription_id, status, attempted_at) helps the monitoring queries. The exact indexes depend on customer query patterns and should be revisited as usage matures.
The API surface
The dashboard view is the highest-leverage customer surface. A per-subscription deliveries list with status and timestamp and event-type, filterable by status and date range, accounts for most of the customer interactions with receipt data. The detail page for a single delivery shows the full request and response, with a copy-as-curl button that reconstructs the attempt for local replay.
The programmatic API surface has three endpoints: GET deliveries with filters and cursor pagination, GET delivery/{id} for the full detail, and POST delivery/{id}/replay for triggering a retry. The replay endpoint is the most commonly used and pays for itself in support time saved. The customers who can replay a delivery themselves do not need to ask us to do it for them.
The export endpoint completes the set. POST deliveries/export with date range and filters returns a job ID; GET deliveries/export/{job_id} returns the CSV or JSONL file when ready. The export is the workflow for the compliance and reconciliation use cases, which need the data in spreadsheets or analytical pipelines rather than in the UI.
What receipts should not include
The temptation is to include everything in the receipt: full request body, full response body, all headers, internal trace IDs, sender-side queue state. The trap is storage cost, which compounds at the per-delivery rate. For a sender pushing 10 million events per month across 1000 subscriptions, each kilobyte of receipt content adds 10 GB of storage per month, multiplied by retention period.
The discipline is to include what supports the customer workflows and exclude what does not. The request body is usually duplicated in the event store and does not need to be in the receipt. The response body should be truncated to a few kilobytes with a flag indicating truncation. Internal trace IDs belong in our logs, not in customer-facing receipts. Headers should include only those that are part of the integration contract: signature, timestamp, event metadata, content-type.
The receipt is a customer-facing surface, which means the data in it has the same sensitivity as the data in customer endpoints. Treating receipts as casually-stored debug logs is a mistake that creates compliance exposure proportional to the integration scale.
The reconciliation contract
The most underappreciated use of delivery receipts is reconciliation against external systems. A customer integrating webhooks with their internal accounting system, their CRM, or their data warehouse needs to be able to ask "did we receive every event we should have received in this period, and did our downstream system record each one?"
The reconciliation answer requires that delivery receipts cover every event-subscription pair, that the customer can pull the receipts efficiently for the period in question, and that the receipts include enough information to match against downstream state. The matching is usually on event_id, which means the receipt schema needs to include event_id as a first-class column rather than burying it in the response body.
The reconciliation contract is also what justifies the retention period. A customer who closes their books quarterly needs three months of receipts available; a customer with annual external audits needs twelve months plus a buffer. The retention policy should be configurable per plan, with the default biased toward longer rather than shorter.
Three operational signals
The platform-side metrics that matter most are delivery success rate per subscription with sliding-window calculation rather than cumulative, customer-side receipt-query rate as proxy for active integration health, and storage growth rate per customer as cost-monitoring signal.
The first signal tells you which integrations are failing in ways customers will eventually complain about. The second tells you which customers are actually using receipts versus which are paying for the storage without engaging with it. The third tells you which customers are approaching the size where receipts need archival or summarization rather than indefinite hot retention.
What we do across the four products
WebhookVault has the most complete receipt implementation across our products because the product is fundamentally about capturing and inspecting webhook traffic. Every captured request is a receipt by another name, and the dashboard already supports the deliveries-list and detail views that other webhook providers retrofit on top of their core product.
CronPing has a similar implementation for monitor check receipts, where each check generates a record customers can query for SLA reporting and incident timeline reconstruction. The pattern carries over from webhook delivery receipts directly: stable IDs, indexed-by-monitor, exportable for offline analysis.
FlagBit has flag-evaluation receipts that serve the audit use case for compliance-sensitive customers. Every flag evaluation is logged with the input context, the evaluation result, and the rule that produced it, accessible through the same dashboard and export patterns.
DocuMint has generation receipts that record every PDF generated, the template used, and the input data hash. The hash rather than the raw input keeps the audit trail useful without storing customer financial data we do not need.
The deeper observation is that delivery receipts and their analogs are the load-bearing customer-facing audit surface for any product whose value depends on doing things customers cannot directly observe. The investment pays back in customer trust, in support time saved, and in the compliance posture that distinguishes serious B2B SaaS from hobbyist projects.
Our WebhookVault product is the clearest implementation of this pattern across our four products. CronPing applies the same pattern to monitor checks, FlagBit to flag evaluations, and DocuMint to PDF generation events. All four converge on stable IDs plus indexed lookup plus export endpoints as the customer-facing surface for audit-grade activity history.