verifyWebhook in @sume-com/sdk: a Next.js route that returns 204

Use verifyWebhook from @sume-com/sdk in a fetch-style route: read request.text(), verify, store, return 204. It handles rotation headers.

5 min readSume
All posts

verifyWebhook from @sume-com/sdk checks the sume-v1 HMAC signature for you. In a fetch-style route, read await request.text() before any parsing, pass it with the headers and your secret, return 401 on failure, store the event, and answer 204. It is async, takes no client and makes no request.

The route

This matches the SDK doc. The secret comes from SUME_COM_WEBHOOK_SIGNING_SECRET, the name Sume's delivery worker uses. Read it from the dashboard Webhooks tab or GET /v1/webhooks/signing-secret. The guard on the secret makes a missing variable a loud failure, not a silent pass.

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

export async function POST(request: Request) {
  const secret = process.env.SUME_COM_WEBHOOK_SIGNING_SECRET;
  if (!secret) return new Response("no secret", { status: 500 });
  const body = await request.text(); // raw, before JSON.parse

  const ok = await verifyWebhook({
    body,
    headers: request.headers,
    secret,
  });
  if (!ok) return new Response("bad signature", { status: 401 });

  const event = JSON.parse(body);
  await record(event.job_id ?? event.request_id, event);
  return new Response(null, { status: 204 });
}

Why 204 and a fast reply

Sume gives each attempt 10 seconds and tries up to 10 times, 30 seconds apart. Store the event durably, return a 2xx, and do slow work after. A slow handler gets the same event retried.

Rotation and versions

During a rotation window the signature header holds two entries, newest first. verifyWebhook in @sume-com/sdk 0.2.0, the release the docs name as current, handles that. A hand-rolled equality check does not, so prefer the SDK function or the docs verifier that loops over entries.

Idempotent storage

Key on job_id for job events and on request_id for run events. Retries, Redeliver and your own sweeps can produce the same event twice, so the second insert must be harmless.

Related posts

More in Developers

All Developers posts

Written by Sume