# Stripe on AWS Lambda: webhooks, timeouts, and duplicate deliveries ("stripe aws lambda")

## TL;DR
Almost every Stripe-on-Lambda failure falls into three buckets: API Gateway mangles the webhook body so signature verification fails, the default 3-second timeout kills in-flight Stripe API calls, and Lambda retries deliver the same webhook event twice. Raise the timeout to 30s, verify signatures against the raw unparsed body, and dedupe events by event id. Those three fixes solve the vast majority of agent-built Lambda payment flows.

```text
stripe aws lambda
```

## Steps

1. Raise the function timeout to 30 seconds. Lambda's default is 3 seconds, and a single Stripe API call plus a cold start blows past it. Success check: no more `Task timed out after 3.00 seconds` in CloudWatch during payment calls.

2. Verify webhook signatures against the RAW body, not parsed JSON. API Gateway can re-serialize the payload, which breaks the signature. Configure the integration to pass the body through untouched and read the exact bytes received. Success check: signature verification passes both locally (via the Stripe CLI) and in production.

3. Dedupe webhook events by event id. Stripe retries undelivered webhooks, and Lambda retries failed invocations, so double delivery is normal. Store processed event ids in your datastore and return 200 for repeats without re-running business logic. Success check: a replayed event returns 200 and creates no duplicate charge or fulfillment.

4. Create the Stripe client once at module scope so warm invocations reuse it. Success check: warm-invocation latency drops and no new client setup appears in logs.

5. Send an idempotency key derived from YOUR order id on every create call (payment intent, charge, refund). Success check: a retried Lambda invocation does not create a second payment intent.

## When this applies

- A coding agent generated a Lambda-based Stripe integration that times out, rejects webhooks, or double-charges.
- You are hardening an existing serverless Stripe flow before launch.
- Webhook signature checks pass in local dev but fail after deploy.

## When it doesn't

- Browser-side Stripe.js or Elements issues; those are a different layer.
- Debugging raw Stripe server SDK calls outside serverless.
- Non-AWS serverless runtimes, though the patterns (timeouts, raw body, dedupe) are similar.

## Tool + version compatibility

Stripe API 2024-06 and later, stripe-node v14+ or stripe-python v7+, AWS Lambda Node.js 20 / Python 3.12 runtimes, API Gateway REST and HTTP APIs, Stripe CLI for local webhook testing.

### "stripe webhook signature invalid lambda"
This is the raw-body problem from step 2. Check whether API Gateway or your framework parsed the body before the verification ran.

### "stripe lambda task timed out"
Timeout fix from step 1. If it still times out after 30s, the Stripe call is hanging on network config (VPC with no NAT), not on Stripe.

### "stripe duplicate charge lambda retry"
Dedupe plus idempotency keys (steps 3 and 5). Never rely on "it probably ran once."

## Why it happens

Lambda's execution model (short-lived, automatically retried, payloads proxy-encoded by API Gateway) clashes with what Stripe expects: signatures computed over raw bytes, synchronous API calls that take a second or two, and at-least-once webhook delivery. Agent-generated code usually treats Lambda like an always-on server, so it misses all three.

## Edge cases / pitfalls

- API Gateway HTTP APIs and REST APIs use different payload formats (1.0 vs 2.0). Body decoding must match your API type or signatures still fail.
- Returning a non-200 from a webhook handler triggers Stripe retries AND Lambda retries; always acknowledge before doing slow work, and do the slow work asynchronously.
- Provisioned concurrency fixes cold starts but changes nothing about signatures or dedupe.
- Test webhooks with the Stripe CLI forwarding to a local tunnel rather than hand-crafting payloads.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_ghWr8iakBD9RxX_kCpS6XQ
