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.

4 min readSume
All posts

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.

langgraph releases (read 2026-10-03)
PackageItem
langgraph 1.2.12Response schema support for interrupts
langgraph-cli 0.4.32Listener 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.

Where each wait belongs
WaitEnds whenMechanism
Spend approvalA person approves a priced requestGraph interrupt with a typed answer
RenderThe job is terminalWebhook job.completed, job.failed or job.canceled
Safety netA delivery never arrivesPoll 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 each sume-v1= entry in x-sume-webhook-signature, with a replay window such as five minutes.
  • Look up the thread by job_id. If it is already resumed, return 2xx and 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

All Integrations posts

Written by Sume