Cloudflare Worker for Sume webhooks: log fields a dashboard needs

Cloudflare added Workers Observability to Custom Dashboards on Oct 1. A Sume webhook Worker should log event, job_id, outcome and the secret fingerprint.

5 min readSume
All posts

A Cloudflare Worker that receives Sume webhooks should write one JSON log line per delivery with five fields: event, job_id, verified, fingerprint and status_code. Cloudflare's changelog lists Workers Observability in Custom Dashboards on October 1 (Cloudflare changelog, read 2026-10-04), and a dashboard can only chart what the logs carry. Flat, consistent keys are what make a webhook failure rate or a rotation problem a one-click chart.

Sume's own docs set the contract for what you can rely on. Job webhooks are terminal-only, with the events job.completed, job.failed and job.canceled, and every delivery is signed with HMAC SHA 256 over <timestamp>.<raw_body> (Webhooks).

Why these five fields

Each field answers a question you will ask during an incident. event and job_id come from the JSON body and tell you what finished. verified is the result of the signature check, so a spike means either an attack or a secret mismatch. fingerprint is the x-sume-webhook-secret-fingerprint header, which Sume sends on every delivery and which is the one part of this that is safe to paste into a ticket. Comparing it with the fingerprint in the dashboard tells you whether your Worker holds the current secret without either side revealing it.

During a rotation the signature header carries one sume-v1= entry per live secret for 24 hours. The SDK's verifier accepts any match, so a Worker running it keeps verifying across a rotation, and the fingerprint field shows when senders have moved to the new secret (Verifying webhooks).

Fields to log per Sume webhook delivery (Sume docs, read 2026-10-04)
FieldSourceUse on a dashboard
eventJSON bodySplit completed, failed and canceled
job_idJSON bodyJoin to your own job table
verifiedYour verifier resultAlert on a sudden false rate
fingerprintx-sume-webhook-secret-fingerprintDetect a stale secret after rotation
status_codeYour responseConfirm fast 2xx replies

The Worker

verifyWebhook from @sume-com/sdk is built on WebCrypto, so it imports in Workers without Node built-ins. It returns false for a missing header or an empty secret rather than throwing, and the code below also refuses to run at all without a secret. It reads the raw body before parsing and answers 401 on a bad signature.

import { verifyWebhook } from "@sume-com/sdk";

interface Env { SUME_COM_WEBHOOK_SIGNING_SECRET: string }

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== "POST") return new Response(null, { status: 405 });
    const secret = env.SUME_COM_WEBHOOK_SIGNING_SECRET;
    if (!secret) return new Response("not configured", { status: 500 });
    const body = await request.text();
    const verified = await verifyWebhook({ body, headers: request.headers, secret });
    let parsed: any = {};
    try { parsed = JSON.parse(body); } catch {}
    const status = verified ? 204 : 401;
    console.log(JSON.stringify({
      msg: "sume_webhook",
      event: parsed.event ?? "unknown",
      job_id: parsed.job_id ?? parsed.request_id ?? null,
      verified,
      fingerprint: request.headers.get("x-sume-webhook-secret-fingerprint"),
      status_code: status,
    }));
    return new Response(null, { status });
  },
};

Keep the Worker thin

Reply fast and do the real work elsewhere. Dedupe on job_id for job webhooks, since a delivery can arrive more than once, and keep polling GET /v1/jobs/{id} as a fallback for a delivery that never arrives. Logging the body itself is not needed and would put result URLs into your log store, so log identifiers only.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume