How AWS SQS's At-Least-Once Delivery Model Changes Webhook Reliability
SQS isn't glamorous. It's been around since 2006. And it's still the most battle-tested at-least-once message delivery system on the planet. When webhooks must not be lost, this is what serious teams reach for.
SQS is not a 2024 startup with a growth-hacking blog. It launched in 2006. For two decades, it has been the thing serious teams reach for when they cannot afford to lose a message. It does not have a clever logo. It does not have a community Slack. It has published SLAs and an argument that has held up under planetary-scale load for twenty years. Review the AWS SQS documentation for current SLA terms.
If you are building a webhook processing pipeline and you need delivery guarantees you can stake a business on, you should understand what SQS actually provides — and what it does not. The marketing copy says "reliable." The documentation tells you what "reliable" actually means. For a framework to evaluate reliability claims across vendors, see the webhook vendor evaluation checklist.
What SQS Actually Guarantees
The core design is deceptively simple. A message enters the queue and stays there until a consumer explicitly deletes it. No delete, no gone. A visibility timeout — configurable, default 30 seconds — prevents two consumers from processing the same message simultaneously. If a consumer fails to delete the message within the visibility timeout, it becomes visible again and another consumer picks it up.
That design gives you at-least-once delivery — a message will be delivered at least one time and may be delivered more than once. A message will be delivered at least one time. It may be delivered more than once — on network failures, on visibility timeout expiry, on consumer crashes mid-process. This is not a bug. It is a documented property of the standard queue. Your consumer code must be idempotent. SQS is honest about this in a way that some systems are not.
Standard queue characteristics:
- At-least-once delivery
- Best-effort ordering (not guaranteed)
- Nearly unlimited throughput
- $0.40 per million requests
The reliability story here is real. SQS publishes an SLA of 99.9% availability. Not "we try hard." A number with a dollar figure attached if they miss it. That is a different class of commitment than a managed SaaS that tells you delivery is "reliable."
FIFO: When Order and Exactly-Once Matter
The standard queue's "best-effort ordering" is genuinely best-effort. For most webhook processing, this is fine — a Stripe invoice.paid event doesn't need to arrive before customer.subscription.updated in strict order. But for payment reconciliation pipelines, audit logs, or any workload where sequence integrity matters, best-effort is not enough.
SQS FIFO queues give you two things the standard queue does not:
Strict ordering per message group. Events with the same MessageGroupId are delivered in the exact order they were sent. Different message groups can be processed in parallel — the ordering guarantee is scoped to the group, not the entire queue.
Exactly-once processing within a 5-minute deduplication window. A message sent with a MessageDeduplicationId (or with content-based deduplication enabled) will be deduplicated against any other message with the same ID sent within 5 minutes. Duplicates are silently discarded. This is the only widely-deployed exactly-once primitive that scales to AWS's throughput numbers.
import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";
const client = new SQSClient({ region: "us-east-1" });
async function enqueueWebhookEvent(event: WebhookEvent): Promise<void> {
await client.send(new SendMessageCommand({
QueueUrl: process.env.FIFO_QUEUE_URL,
MessageBody: JSON.stringify(event),
// Group by customer — events for the same customer stay ordered
MessageGroupId: event.customerId,
// Deduplicate by provider event ID — Stripe sends idempotency keys
MessageDeduplicationId: event.providerEventId,
}));
}
The FIFO tradeoff is throughput: 3,000 messages per second with batching, versus "nearly unlimited" for standard. For most webhook workloads, 3,000/sec is not a constraint. If you are ingesting firehose-volume webhook traffic, standard queue with application-level idempotency is the right call.
The Webhook Architecture Pattern
The architecture that serious AWS teams use for webhook reliability looks like this:
Webhook Provider
│
▼
API Gateway / Lambda (acknowledge fast — returns 200 in <500ms)
│
▼
SQS Queue (standard or FIFO depending on ordering needs)
│
▼
Worker Lambda / ECS Task (processes idempotently)
│
▼
Dead Letter Queue (max receive count exceeded — poison message isolation)
The Lambda at the ingress does three things: verify the signature, put the message on the queue, return 200. That's it. Processing happens asynchronously in the worker. The DLQ catches events that fail processing repeatedly — not delivery failures, processing failures. Your operations team reviews DLQ contents when the alarm fires.
SNS delivery policies add another layer when you need fan-out. A single Stripe webhook can trigger an SNS topic that fans out to multiple SQS queues — one for your billing worker, one for your analytics pipeline, one for your email worker. SNS supports linear and exponential backoff retry policies for each subscription, and each subscription can have its own DLQ. The whole structure is declarative via CloudFormation or CDK.
// CDK: Stripe webhook fan-out with per-subscriber DLQs
const stripeTopic = new sns.Topic(this, 'StripeEvents');
const billingDlq = new sqs.Queue(this, 'BillingDlq');
const billingQueue = new sqs.Queue(this, 'BillingQueue', {
deadLetterQueue: { queue: billingDlq, maxReceiveCount: 3 },
});
const analyticsDlq = new sqs.Queue(this, 'AnalyticsDlq');
const analyticsQueue = new sqs.Queue(this, 'AnalyticsQueue', {
deadLetterQueue: { queue: analyticsDlq, maxReceiveCount: 5 },
});
stripeTopic.addSubscription(new snsSubscriptions.SqsSubscription(billingQueue));
stripeTopic.addSubscription(new snsSubscriptions.SqsSubscription(analyticsQueue));
This is not a toy. Teams at serious scale run exactly this architecture in production. It works. The operational complexity is real, but so are the guarantees.
Where Hookdeck Fits
Hookdeck is the managed product that approximates SQS-level delivery reliability without operating the Lambda-SQS-worker-DLQ pipeline yourself. Read G2 reviews of Hookdeck for real-user takes on their delivery reliability at scale. At-least-once delivery is documented. Automatic retries — up to 50 attempts with configurable backoff. SOC 2 Type II certified. A purpose-built interface for inspecting webhook payloads and debugging failures.
For teams not on AWS, or teams that are on AWS but do not want to operate and maintain the async processing infrastructure, Hookdeck is the closest managed equivalent to what you would build with SQS. It handles the queue, the retry logic, the DLQ equivalent (issues), and the payload inspection in a single product.
The honest comparison: Hookdeck has not published a formal delivery SLA with financial penalties the way AWS has. SQS's 99.9% availability SLA comes with service credits. Hookdeck's delivery reliability is based on reputation and the published retry count. For most teams, that is fine. For teams in regulated industries or with contractual SLA commitments to their customers, the AWS paperwork is meaningful.
Hookdeck pricing starts at $39/month for the team plan. That is a reasonable number for teams that want managed webhook infrastructure without AWS build costs.
Where HookTunnel Fits
HookTunnel is a different thing entirely. It does not compete with SQS. It sits at a different layer of the architecture — the inbound HTTP boundary, before your queue.
The problem SQS solves is durable async processing after you have received a webhook. The problem HookTunnel solves is capturing and observing what arrived at the HTTP boundary — the raw payload, every header, the exact timestamp, the provider's delivery attempt metadata — regardless of what happens downstream.
These are complementary concerns. The architecture with both looks like:
Webhook Provider
│
▼
HookTunnel (captures raw HTTP request — payload, headers, timing)
│
▼
Your Lambda handler (ACKs fast, enqueues)
│
▼
SQS Queue
│
▼
Worker → DLQ on failure
Where HookTunnel adds specific value on top of SQS:
Forensics before the queue. When a message hits the DLQ and you cannot figure out why, the question is often "what was the exact payload?" If your Lambda handler wrote the raw body to SQS without capturing headers, you have lost information. HookTunnel stores the complete HTTP request — body, headers, query params — for every event. You can go back and look at what arrived, independent of what your queue contains.
Replay against your endpoint. HookTunnel Pro includes replay. If you deploy a bug that broke your webhook handler and need to reprocess the last 6 hours of Stripe events, you replay them from HookTunnel's captured history rather than contacting Stripe support and asking them to resend. SQS messages that were successfully processed and deleted are gone. HookTunnel's capture history is separate.
Debug before build. When you are building the SQS integration and need to understand exactly what Stripe sends for a given event type — the structure, the headers, the timing — you point Stripe at a HookTunnel hook and capture real events. No mocking. No stub JSON. The real thing.
TCO: SQS pricing is consumption-based and very cheap at low volumes — check SQS pricing for current rates — but the pipeline has fixed operational costs: Lambda configuration, IAM roles, DLQ alarms, CloudWatch dashboards. HookTunnel Pro is $19/month flat via our pricing page. Free tier gives you one hook with 24-hour history. For teams that want forensics and replay without standing up the full Lambda-SQS pipeline, HookTunnel is the faster path. For teams that have already built the SQS pipeline and want better observability at the boundary, HookTunnel slots in alongside it. See also: webhook retry storms — a pattern that affects SQS-backed pipelines as much as raw HTTP handlers.
The Honest Assessment
SQS is infrastructure you can bet your business on. The at-least-once guarantee with published SLA, the FIFO exactly-once deduplication window, the SNS fan-out integration, the DLQ isolation — this is a genuinely excellent system built by people who have been thinking about message delivery for twenty years. If you need formal delivery guarantees with financial SLA commitments, build the SQS pipeline. The operational complexity is the price of those guarantees.
Hookdeck is the managed path to similar guarantees for teams that cannot or will not operate the AWS pipeline. Solid product. SOC 2 certified. Forty-something dollars a month gets you managed at-least-once delivery with 50 retries. The gap is the published SLA — you are trusting their infrastructure rather than AWS's SLA paperwork.
HookTunnel is the boundary layer that neither SQS nor Hookdeck covers: capture and forensics at the inbound HTTP edge. If your team is drowning in webhook incidents before you have finished building the SQS pipeline, there is a $19/month layer that gives you payload capture, history, and replay today. Not mutually exclusive. The two-layer architecture — HookTunnel for forensics, SQS for guarantees — is a clean split of responsibilities.
Make your own call. But there is a new tool in the neighborhood that is worth understanding before you commit three sprints to the full AWS pipeline.
Stop guessing. Start proving.
Generate a webhook URL in one click. No signup required.
Get started free →