AWS Lambda webhook receiver for Sume: function URL and HMAC
Give Sume a Lambda function URL with auth type NONE, decode the event body, check the sume-v1 HMAC, and answer 204 inside the 10-second window.

To use AWS Lambda as a Sume webhook receiver, create a function URL with auth type NONE, pass it as communication.webhook_url when you start a run, and check Sume's signature in the handler: decode event["body"] from base64 when isBase64Encoded is true, compute HMAC-SHA256 over <timestamp>.<raw_body>, and accept the delivery when any sume-v1= entry matches. Then answer 204 well inside Sume's 10-second attempt window.
AWS facts come from the Lambda Developer Guide: Invoking function URLs, Control access to function URLs, function timeout, and the webhook tutorial. Sume facts come from Run webhooks, Webhooks, and Runs and results. All were read on 2026-09-27. Sume has no Lambda integration or package: the handler below is plain Python. Signing, retries, and rotation in general are covered in Signed webhooks for Sume video runs.
Which function URL settings does a Sume webhook need?
Five settings decide whether a delivery reaches your code in time. Sume refuses localhost, private-network, and non-HTTPS webhook URLs; a function URL is none of those, and Sume's webhook URL rules list the other refusals.
| Setting | For Sume | Why |
|---|---|---|
| Auth type | NONE | AWS_IAM requires SigV4-signed requests. Sume signs deliveries with its own HMAC headers instead, which the handler checks. |
| Resource-based policy | Allow lambda:InvokeFunctionUrl and lambda:InvokeFunction | Needed even with NONE; without it, callers get 403 Forbidden. The console and AWS SAM create it; with the AWS CLI or CloudFormation you add it yourself. |
| Timeout | Up to 10 seconds | Lambda's default is 3 seconds and the maximum is 900. Sume gives each attempt 10 seconds, and a slow answer is retried. |
| Reserved concurrency | Room for concurrent deliveries | Above it, the URL answers 429. Sume retries, and run webhooks honor your Retry-After on a 429. |
| The URL | https://<url-id>.lambda-url.<region>.on.aws | HTTPS on the default port; current Sume code refuses a URL with a non-default port. The URL never changes, and a deleted one cannot be recovered. |
How do I read the raw body from a Lambda event?
Lambda maps each request to an event in payload format version 2.0: headers holds the request headers as key-value pairs, and body is a string, base64-encoded when the request's content type is binary, which isBase64Encoded reports. Decode first, verify those bytes, then parse JSON. The check follows Python webhook HMAC verification, adapted to the event: it lowercases header names, refuses an empty secret, and compares every sume-v1= entry in constant time. It reads the secret from an environment variable to stay short; AWS recommends Secrets Manager instead for API keys and other sensitive values.
On a Node.js runtime, verifyWebhook from @sume-com/sdk runs the same check: it needs Node 18 or later, accepts the decoded bytes as a typed array, and reads event.headers as a plain object.
import base64, hashlib, hmac, json, os, time
SECRET = os.environ["SUME_COM_WEBHOOK_SIGNING_SECRET"].encode()
def lambda_handler(event, context):
body = event.get("body") or ""
raw = base64.b64decode(body) if event.get("isBase64Encoded") else body.encode()
headers = {k.lower(): v for k, v in (event.get("headers") or {}).items()}
ts = headers.get("x-sume-webhook-timestamp", "")
if not SECRET or not ts.isdecimal() or abs(time.time() - int(ts)) > 300:
return {"statusCode": 401} # no secret, or outside the 5-minute window
digest = hmac.new(SECRET, f"{int(ts)}.".encode() + raw, hashlib.sha256).hexdigest()
expected = f"sume-v1={digest}".encode()
matched = False
for entry in headers.get("x-sume-webhook-signature", "").split(","):
matched = hmac.compare_digest(entry.strip().encode(), expected) or matched
if not matched:
return {"statusCode": 401}
event_body = json.loads(raw)
record_once(event_body) # your queue or table, keyed on request_id or job_id
return {"statusCode": 204}What changes from AWS's webhook tutorial?
AWS's own tutorial builds a webhook endpoint on a function URL with auth type NONE and an HMAC check. That check does not match Sume's scheme, so change four things:
- What is signed. The tutorial HMACs the body alone and reads one
x-webhook-signatureheader. Sume signs<timestamp>.<raw_body>and sendsx-sume-webhook-timestampwithx-sume-webhook-signature. - Which bytes. The tutorial hashes
event['body']as it arrives. Decode it first whenisBase64Encodedis true. - The comparison. The tutorial's Node.js version compares with
===. Compare in constant time, as its Python version does withhmac.compare_digest, which Python documents as designed to prevent timing analysis. - The header format. For 24 hours after a secret rotation, Sume sends two comma-separated
sume-v1=entries, newest first. Accept a match on any entry: a check that compares the whole header fails every delivery in that window.
Why not wait for the video inside the Lambda function?
Because a run can outlast the invocation. A Lambda timeout is at most 900 seconds (15 minutes), while long-form host video typically finishes in 15 to 30 minutes, and Sume force-finalizes a run as failed at most 90 minutes after created_at. A function that times out while waiting does not stop the run: it keeps running and billing.
So start the run from any service with the function URL as communication.webhook_url, store data.id, and return. Generation jobs take the same URL as webhook_url or its alias callback_url, and one verifier covers run and job deliveries.
What should the handler do once the signature checks out?
Record the event where other code can pick it up, answer 204, and do the slow work outside the handler: Sume retries an answer that misses its 10-second attempt window. Dedupe on request_id for runs and job_id for jobs, and keep a read of result_url as the backup; Signed webhooks for Sume video runs covers the other delivery rules.
Sources
- Run webhooks
- Webhooks
- Verifying webhooks
- Runs and results
- Jobs and results
- Formats
- Create a run
- Format cookbook
- TypeScript SDK
- AWS Lambda: Invoking Lambda function URLs (read 2026-09-27)
- AWS Lambda: Control access to function URLs (read 2026-09-27)
- AWS Lambda: Creating and managing function URLs (read 2026-09-27)
- AWS Lambda: Tutorial: Creating a webhook endpoint using a function URL (read 2026-09-27)
- AWS Lambda: Configure function timeout (read 2026-09-27)
- AWS Lambda: Working with environment variables (read 2026-09-27)
- Python: hmac (read 2026-09-27)
Related posts
More in Integrations
- Bubble API Connector: generate AI video with the Sume API
Set up Bubble's API Connector for Sume: the key in a private header, a manual response so setup costs nothing, and a backend poll of the job.
- Claude Agent SDK MCP server: connect Sume with an API key
Add Sume's hosted MCP server to the Claude Agent SDK with an API-key header, allow only the tools you need, and dry-run paid calls before submitting.
- Claude API MCP connector with Sume: what works today
The Claude API MCP connector has no documented way to authenticate to Sume's hosted MCP today. Why, and what to use instead, like the Agent SDK.
- CrewAI video generation with a Sume Agent Completions tool
Give a CrewAI agent a BaseTool that hands a video brief to Sume Agent Completions with a spend cap, then reads the agent.run for the finished video.
Written by Sume