All posts
3 min readConvoy Team

Resume Your Durable Lambda Directly: No Webhook Required

Convoy can now resume your AWS Lambda durable function directly — a scoped IAM role replaces the webhook endpoint, receiver Lambda, and signing scheme.

productannouncementengineering

AWS Lambda durable functions solved half of the batch problem: your workflow can call wait_for_callback, checkpoint, and suspend at zero compute cost — for up to a year — until something resumes it with a result. The other half was still on you: standing up a webhook receiver, protecting a public endpoint, verifying signatures, and translating the webhook back into a SendDurableExecutionCallbackSuccess call.

Today we're shipping direct durable callbacks: Convoy resumes your durable function itself. No webhook endpoint, no receiver Lambda, no signing scheme. Your workflow submits cargo, suspends, and wakes up with the result.

The webhook tax

The webhook pattern works, but look at what it actually costs for a durable workflow:

  • A public endpoint (Function URL or API Gateway) you have to protect.
  • A receiver Lambda whose only job is to parse the webhook and call the Lambda callback API.
  • A webhook auth scheme — signatures, secrets, rotation — that's your problem to get right.
  • An SSRF and replay surface that exists because there's a URL at all.

Direct delivery removes every line of that list. IAM and SigV4 are the auth, and a consumed callback ID can't be resumed twice.

How it works

  1. Your durable workflow calls wait_for_callback — the SDK hands your submitter a one-time callback ID.
  2. The submitter POSTs to /cargo/load with a structured callback object instead of a callback_url:
body = {
    "params": {
        "model": "claude-haiku-4-5",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": prompt}],
    },
    "callback": {
        "type": "aws_durable_callback",
        "connection_id": os.environ["CONVOY_AWS_CONNECTION_ID"],
        "callback_id": callback_id,
    },
}
  1. Convoy batches and processes the request — minutes to hours, at batch prices. Your function is suspended the whole time, costing nothing.
  2. When the cargo completes, Convoy's delivery worker assumes a role in your account and calls SendDurableExecutionCallbackSuccess with the result. Your workflow resumes exactly where it left off:
{
  "cargo_id": "cargo_a1b2c3...",
  "success": true,
  "response": { "content": ["..."], "usage": {} },
  "response_truncated": false,
  "result_url": "https://api.cnvy.ai/cargo/cargo_a1b2c3.../result",
  "metadata": { "your": "metadata" }
}

AWS caps the durable callback result at 256 KB. If your envelope would exceed it, Convoy sets response_truncated: true and your workflow's next step fetches the full body from result_url — one GET with your API key.

Failures are first-class too: a failed cargo raises a CallbackError (ConvoyCargoFailed) inside your workflow, and an optional "heartbeat": true flag makes Convoy send liveness heartbeats roughly every 5 minutes so a lost cargo trips your heartbeatTimeout instead of waiting out a 26-hour callback timeout.

The security model

This only works if the cross-account story is airtight, so we made it narrow by construction:

  • You create an IAM role that trusts Convoy's delivery account only when the caller presents your connection's unique ExternalId — a cnvyext_... secret shown exactly once.
  • The role grants only the three lambda:SendDurableExecutionCallback* actions, on only the durable function you name.
  • Convoy additionally pins a session policy to those actions on every AssumeRole, and encrypts your callback ID at rest — it's a capability token and is treated like one.

Convoy can resume your workflow and do literally nothing else in your account. Setup is one wizard run in the dashboard's AWS tab plus one IAM role — we ship ready-made Terraform and CloudFormation for it, and a verification probe confirms the grant with a side-effect-free dry run before any cargo flows.

Try it

If you're already resuming durable functions through a webhook receiver, you can delete that receiver today — both paths resume the same workflow, so migrating is a one-field change in your submitter. The full guide is in the docs, and this is just one of eight AWS-native delivery targets we're launching — see the announcement for SQS, Kinesis, EventBridge, S3, and Step Functions delivery.

New to Convoy? Create an account and submit your first batch in minutes — or start with why batch inference cuts your AI bill.

More posts

All Aboard?

Ready to simplify your batch processing and start saving on AI costs? Get started in minutes.