LangGraph interrupt or wait: resume a graph from a Sume webhook
A LangGraph interrupt is for a human decision, not a video render. Pause for approval, then resume the graph from a signed Sume webhook keyed by job_id.

Use a LangGraph interrupt for the human decision to spend, and use a Sume webhook, with polling as a backup, to learn that the render finished. The langgraph releases page lists langgraph 1.2.12 adding response schema support to interrupts, which makes the approval step typed; it does not make an interrupt a good place to wait for a job.
Mixing the two is a common mistake. An interrupt blocks on a person, who answers in seconds or hours. A video job finishes on its own schedule and tells you through a terminal event.
What the release page lists
Relevant items only.
| Package | Item |
|---|---|
| langgraph 1.2.12 | Response schema support for interrupts |
| langgraph-cli 0.4.32 | Listener deployments |
Two different waits
The approval wait ends when a person answers. The job wait ends when Sume reports a terminal state. Sume jobs move through queued, processing and then completed, failed or canceled, and a queued job is a normal accepted state, not a failure.
| Wait | Ends when | Mechanism |
|---|---|---|
| Spend approval | A person approves a priced request | Graph interrupt with a typed answer |
| Render | The job is terminal | Webhook job.completed, job.failed or job.canceled |
| Safety net | A delivery never arrives | Poll status_url with backoff |
State to keep in the graph
Store identifiers, not media. After the approved submit, put the job id and the status URL in graph state, so any worker can pick the thread up again. Sume documents job_id as the idempotency key for webhook receivers, so use it as the key that resumes the graph exactly once.
{
"approved": true,
"job_id": "job_...",
"status_url": "https://api.sume.com/v1/jobs/job_.../status",
"submitted_with_idempotency_key": "campaign-42-shot-3"
}The resume path
The receiver is a small HTTP handler outside the graph.
- Verify the signature on the raw body first: HMAC SHA 256 over
<timestamp>.<raw_body>, compared against eachsume-v1=entry inx-sume-webhook-signature, with a replay window such as five minutes. - Look up the thread by
job_id. If it is already resumed, return2xxand do nothing. - Store the event durably, return
2xx, then resume the graph with the result URL from the payload. - A job that failed or was canceled resumes the graph down a different edge, not a retry of the paid create.
Why not wait inside the interrupt
An interrupt keeps a graph thread parked, which is cheap, but it also ties the resume to whoever calls back with an answer. If a render sat behind an interrupt, you would need something to answer it. A webhook handler can do that, yet then the graph has no way to tell a human approval from a machine event unless you encode it in the response schema. Keeping the two waits separate avoids the problem: approval is one interrupt, the render is a second node that simply ends when the handler marks the thread ready.
For long video work the handler is also the right place to write the result URL into your own storage, so the graph state only ever carries identifiers.
Do not resubmit on timeout
If a graph node times out while waiting, the job keeps running and still bills. Sume's guidance is to continue with the status URL and never submit a new paid job for the same intent; retrying the submit itself is fine only with the same Idempotency-Key.
Webhook delivery is up to 10 attempts, 30 seconds apart by default, with a 10 second timeout per attempt. After that the job still reached its real terminal state, which is why the poll fallback matters.
Sources
Related posts
More in Integrations
- Mastra eager tool execution: dry-run Sume calls first
Mastra 1.71 can start a tool once its own arguments are complete. For paid Sume generation that means a stable idempotency_key and a dry run before any spend.
- Mastra 1.72 crash recovery and leases: checkpoint the Sume job id
Mastra 1.72 adds multi-worker task leases and crash recovery. Store the Sume job id before waiting so a recovered worker polls instead of paying twice.
- n8n 2.41.6 task runner and a Sume webhook verifier that never throws
n8n 2.41.6 keeps its task runner alive on unhandled rejections. Write the Sume webhook check so a bad signature returns false; answer 2xx only after storing.
- OpenAI Agents SDK 0.23 MCP listing limits and Sume tools
openai-agents-python 0.23 adds configurable MCP listing page limits. What that means for Sume's hosted MCP, where the tool list depends on your OAuth scope.
Written by Sume