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.

Write the signature check for a Sume webhook as a function that returns true or false and never throws, and let the workflow decide what a false means. The n8n releases page lists 2.41.6 as stable and says it keeps the task runner alive on an unhandled rejection, which is a good safety net but a poor reason to let a malformed header raise an exception.
A webhook receiver sees hostile and broken input as a matter of course: missing headers, empty bodies, a timestamp that is not a number. The verifier should absorb all of it.
What the release page lists
Relevant items only.
| Release | Item |
|---|---|
| 2.41.6 stable | Task runner stays alive on unhandled rejection |
| 2.42.0 | Improved OpenTelemetry export |
| 2.42.0 | API workflow creation |
| 2.42.0 | Agent builder layout changes |
What Sume sends
A Sume job webhook is sent in mode: "webhook" with a public HTTPS webhook_url. It carries one of three terminal events: job.completed, job.failed or job.canceled. The body is signed with HMAC SHA 256 over <timestamp>.<raw_body>, and the headers are x-sume-webhook-timestamp and x-sume-webhook-signature: sume-v1=<hex>.
During a signing-secret rotation the signature header holds one sume-v1= entry per live secret, comma separated. Accept the delivery when any entry matches.
A verifier that returns false
The check below refuses an empty secret, rejects a bad timestamp and a stale one, and compares every entry. It never raises on header shape, so the only thing the surrounding workflow has to branch on is a boolean.
import crypto from "node:crypto";
export function verifySume(rawBody, timestamp, header, secret, tolerance = 300) {
if (!secret || typeof header !== "string") return false;
const ts = Number(timestamp);
if (!Number.isFinite(ts)) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - ts) > tolerance) return false;
const digest = crypto.createHmac("sha256", secret)
.update(`${ts}.${rawBody}`).digest("hex");
const expected = Buffer.from(`sume-v1=${digest}`);
let ok = false;
for (const entry of header.split(",")) {
const got = Buffer.from(entry.trim());
if (got.length === expected.length && crypto.timingSafeEqual(got, expected)) ok = true;
}
return ok;
}Order of operations in the workflow
The shape of the receiving workflow matters more than the node types.
- Capture the raw body exactly as received. Re-serialized JSON will not match the signature.
- Run the verifier. On false, stop the branch and return a non-2xx so the sender knows delivery failed; do not process the payload.
- Write the event to storage keyed by
job_id, then answer2xx. Sume retries on network errors and non-2xx responses. - Only after storing, fan out to Slack, storage or the next step.
Retries are bounded
Sume tries a delivery up to 10 times in total, with a fixed delay between attempts of 30 seconds by default and a 10 second timeout per attempt. A workflow that does slow work before answering burns that budget and gets the same event again.
Use job_id as the idempotency key on your side, so a repeated event is a no-op. Ten failed attempts leave a failed delivery and a job that still reached its terminal state, so keep status_url polling available, or ask Sume to redeliver with POST /v1/jobs/{job_id}/webhook/redeliver.
Tracing with 2.42
If you turn on the improved OpenTelemetry export that 2.42.0 lists, put the Sume job_id on the span that handles the event. It is the one identifier that ties a delivery, a poll and a usage row together.
Sources
Related posts
More in Integrations
- 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.
- A Supabase job table for Sume webhooks: upsert on job_id
Sume retries webhooks up to 10 times. A Postgres table keyed on job_id with ON CONFLICT turns repeat deliveries into no-ops. Schema, SQL and the order of steps.
- Vercel AI SDK tool search maxResults and Sume tool groups
ai@7.0.127 tool search ranks deferred tools with a search() callback and maxResults. How to split Sume's hosted MCP tools into always-on and deferred groups.
- Vercel AI Gateway's new tools and models, and where Sume media fits
AI Gateway added Browserbase tools and audio models. A planner model can route through a gateway while Sume handles the paid media jobs; where to draw the line.
Written by Sume