Lambda Powertools idempotency and Sume's Idempotency-Key: use both
Powertools idempotency guards your Lambda handler; Sume's Idempotency-Key guards the paid submit. How they differ, and how to derive one key from an order id.

Yes, use both, because they guard different things. Powertools for AWS Lambda's idempotency utility stops your handler from running twice for the same event, while Sume's Idempotency-Key header stops a retried paid submit from creating a second job. Derive the Sume key from your own business id, never from the invocation, so that a handler that does run twice still sends the same key.
The Powertools facts come from its idempotency utility page (read 2026-10-11). The Sume facts come from Jobs and results, Generation admission and the submit code on main.
What does each layer protect?
The two keys live in different places and expire on different clocks, which is why one cannot replace the other.
| Powertools idempotency | Sume Idempotency-Key | |
|---|---|---|
| Protects | Your Lambda handler and its return value | The paid submit call to api.sume.com |
| Key | Function name plus a hash of the payload, or fields picked with event_key_jmespath | A string you send: 255 printable characters or fewer |
| Stored in | A DynamoDB table (INPROGRESS, COMPLETE, EXPIRED) | Sume, on the job record |
| Default lifetime | expires_after_seconds is 3600 (1 hour) | Not stated in the docs I read |
| Same key, changed input | payload_validation_jmespath raises IdempotencyValidationError | 409 idempotency_conflict |
Which key should the handler send to Sume?
Build it from the thing a human would call the order: an order id plus a version, or a render slot such as a date. Three rules keep it safe.
- Do not use a fresh UUID per invocation. A re-run then sends a new key and bills a second job.
- Do not reuse a key for a different request. Sume answers
409 idempotency_conflictwhen a key meets a different operation or payload, and the error details hand back thejob_id,job_status,status_urlandresult_urlof the job that already owns the key, so adopt that job instead of minting a new key. - Hash long business keys. The limit is 255 printable characters, and a longer or control-character key is rejected with a 400.
What happens when the Lambda times out mid-submit?
This is the case the two layers were made for. Powertools marks the record INPROGRESS, and if you call register_lambda_context(), a second invocation that arrives after the first one's remaining time has passed treats the record as expired and runs the handler again. If the first run had already reached Sume, the second run sends the same business key, and Sume returns the original job instead of creating another. Without the Sume key, that re-run is a second paid clip.
The same logic covers the 1 hour default. If an event is redelivered after the Powertools record expired, the handler runs again as if new. A key built from the order id still resolves to the first job, as long as Sume still holds that key, which is why the lifetime row above says "not stated" and why you should also keep the job id in your own table.
What should the handler return, and what about 429s?
Return the job id (and status_url) from the idempotent function, not the finished video. Powertools stores that return value, so a replay inside its window gives the same id back, and the video itself arrives later by polling GET /v1/jobs/{id}/status or by a signed webhook. Do not wait for a video inside the handler; the jobs docs call a client timeout a wait that ends, not a job that stops.
One exception to "same key, same job" is worth knowing. When a submit is refused with 429 queue_full, the generation docs say to retry with the same idempotency key once capacity opens. In the current submit code, a job refused at queue admission is the one case where the key is freed, so that retry creates a fresh job rather than returning the dead one. A 429 rate_limited is different: back off using retry-after.
Sources
Related posts
More in Developers
- LangGraph replay re-fires API calls: key Sume submits per fork
LangGraph time travel re-runs every node after the checkpoint, API calls too. Derive the Sume Idempotency-Key from the body so replays dedupe and forks run.
- MCPJam auth debugger on Sume's MCP host: what each step returns
Point MCPJam's auth debugger at mcp.sume.com and read the results: S256-only PKCE, public clients, authorization_code only, a one-hour token, a resource check.
- What did one script_run cost? Sume script_runs and its children
Sume /v1/usage lists script_runs with rows and money per call, and counts script_run_children in includes. Read the cost of one script_run to the cent.
- pending_usd_micros vs held: what Sume's settle sweeper still owns
Sume /v1/usage splits open holds into held and pending_usd_micros. Read the two fields and settle_state to tell parked rows from spend, and when final flips.
Written by Sume