Webhook URL with user:pass@ gets a 400: verify the signature instead

Sume refuses a run webhook_url that carries credentials, plain HTTP or a private host. Authenticate your receiver with the signed headers, not the URL.

4 min readSume
All posts

No, you cannot put a username and password in a Sume communication.webhook_url. Credentials in the URL, plain HTTP, localhost and private ranges all return 400 invalid_request when you create the run, and nothing starts. The way to protect your receiver is to verify the signature that Sume puts on every delivery.

What the create call refuses

The webhook URL rules are the same for a single run and for each item of a bulk queue, because a bulk item is the same body as a single create. A bad URL on item 37 fails the whole bulk create before any queue exists, so check your URLs before you send 100 items.

Sume also checks the URL again at delivery time, not only at create. It does not follow redirects, so a 3xx counts as a failed attempt.

Webhook URL rules for Format runs (read 2026-10-06)
URLResult
https://hooks.example.com/sumeAccepted (public HTTPS, up to 2048 characters)
https://user:pass@hooks.example.com/sume400 invalid_request at create
http://hooks.example.com/sume400 invalid_request at create
https://localhost:3000/sume or a private range400 invalid_request at create
A URL that later answers 301 or 302Failed attempt; Sume does not follow it

What to use instead of a password

Each delivery carries x-sume-webhook-timestamp, x-sume-webhook-signature (sume-v1=<hex>) and x-sume-webhook-secret-fingerprint. The signature is HMAC-SHA256 over <timestamp>.<raw_body> with your workspace signing secret, which you read on the dashboard Webhooks tab or from GET /v1/webhooks/signing-secret with a key that has account:read.

Verify against the raw bytes before you parse JSON, and reject timestamps outside a five-minute window. Compare the fingerprint header with the one next to the secret in the dashboard to confirm both sides hold the same secret. A receiver that refuses to start with an empty secret is safer than one that accepts everything.

  • Verify first, then record the event durably, then answer 2xx within 10 seconds, then do the work.
  • Dedupe on request_id, which equals the run id and repeats on retries.
  • If you need a per-run routing hint, send it in input and look the run up by id on your side; the docs do not describe query-string behavior, so do not rely on it for secrets.

Tradeoffs

A signature proves that Sume sent the body, not that the body is new. A captured delivery replayed inside five minutes still verifies, so the dedupe on request_id matters as much as the signature. Anyone who finds your endpoint URL can still send it junk; the signature check is what makes that harmless.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume