Which API key scope does each Sume webhook endpoint need?

The signing secret needs account:read, rotate and test deliveries need account:write, redeliver needs jobs:write or formats:write. Map each call to a key.

4 min readSume
All posts

Five Sume webhook calls need three different scopes. Reading the signing secret needs account:read. Rotating the secret and sending a test delivery both need account:write. Redelivering a job webhook needs jobs:write, and redelivering a Format run webhook needs formats:write. Your receiver itself needs no API key at all, because it only checks a signature.

The five calls and their scopes

A key that was created for generation work often has none of the account scopes. The call then fails with a permission error even though the key is valid, and the failure looks like an authentication problem in logs. Decide which key does which job before you wire up a deploy pipeline.

Webhook endpoints and the scope each one needs (read 2026-10-05)
CallScopeWhat it does
GET /v1/webhooks/signing-secretaccount:readReturns your workspace signing secret
POST /v1/webhooks/signing-secret/rotateaccount:writeStarts a 24 hour rotation window
POST /v1/webhooks/test-deliveriesaccount:writeSends a dummy webhook.test payload to your URL
POST /v1/jobs/{id}/webhook/redeliverjobs:writeSends a job webhook again
POST /v1/format-runs/{id}/webhook/redeliverformats:writeSends a Format run webhook again

Split keys by purpose

The cleanest split is one key per purpose. A deploy key holds account:read and account:write and is used only by your release tooling to fetch or rotate the secret. A support key holds jobs:write and formats:write and is used by the person or script that replays a missed delivery. Your production submit path keeps whatever generation scopes it already has.

The signing secret is not an API key. The docs say the secret is derived for your workspace, and the same value is on the Webhooks tab of the dashboard. If you only need to read it once, the dashboard avoids minting a scoped key at all.

One credential header

Authenticate with one header only. The API answers 401 when a request carries both Authorization: Bearer and x-api-key, so pick one.

import os

SCOPES = {
    "signing-secret": "account:read",
    "rotate": "account:write",
    "test-deliveries": "account:write",
    "job-redeliver": "jobs:write",
    "format-run-redeliver": "formats:write",
}

def missing(call, key_scopes):
    need = SCOPES[call]
    return None if need in key_scopes else need

have = set(os.environ.get("KEY_SCOPES", "account:read").split(","))
for call in SCOPES:
    print(call, "missing:", missing(call, have))

What goes wrong in practice

Four failure patterns come up when teams first wire webhooks. Redelivery is safe to use during an incident. It sends a fresh timestamp and a fresh signature, and it does not count against the 10 delivery attempts. Your receiver still has to dedupe on job_id or request_id, because the same terminal event can arrive twice.

  • A CI job that reads the secret with a generation-only key and receives a permission error. Add account:read to a separate key, not to the production key.
  • A rotation script that was tested with a read-only key. Rotation is a write, so it needs account:write, and the 24 hour window starts the moment it succeeds.
  • A support engineer who replays a missed Format run delivery with a key that only has jobs:write. The Format run route needs formats:write, and the job route needs jobs:write, so each replay needs its own scope.
  • A service account key used for a Format run call. The docs reject service-account keys for Format runs, so a replay or run through one will not work whatever its scopes are.

Checking a failing call

Keep the check close to the receiver code. When a rotation script fails with a permission error, compare the scope in the table with the scopes shown for that key in the dashboard. After a rotation, the delivery header x-sume-webhook-secret-fingerprint names the new secret from that moment, so you can confirm the right secret reached your receiver.

Test before you rely on it

Use the dummy webhook.test payload to confirm a new deploy before real jobs depend on it. It carries no job_id, so your handler must accept an event without one. The SDK page on verifying webhooks also says an unknown event should answer 204, not 500, so a new event type never causes a retry storm.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume