Bulk Format run 403 workspace_key_required: an agency's fix

A personal key on a team workspace Format returns 403 workspace_key_required, and a service-account key fails too. Which key to mint for Sume bulk runs.

2 min readSume
All posts

Your key was created outside the team workspace that owns the Format. The bulk runs docs list workspace_key_required as 403 with the instruction to use a key created in details.workspace_id. This hits agencies first, because they keep client Formats in a shared team workspace while engineers hold personal keys.

Three keys that fail, one that works

Bulk run auth, read 2026-10-03
KeyResultFix
Personal key, team Format403 workspace_key_requiredCreate a key inside the workspace in details.workspace_id
Service-account key403 insufficient_scope, reason service_account_format_runs_unsupportedUse a user API key
Older key without scopes403 insufficient_scopeMint a new key; scopes cannot be patched
User key made in the team workspace, with formats:write and formats:read202Works

Scopes

  • formats:write creates the queue (and single runs and cancels).
  • formats:read polls GET /v1/format-run-queues/{id}. A key with write only can create but not poll.
  • Keys created before the Format API-call trigger shipped do not carry these scopes.

Why a 404 can be the same problem

A Format that is archived, outside your key's workspace, or owned by a team you are not in comes back as format_not_found, not 403. If you have the right scopes and still see 404, check the workspace the key was made in before you check the handle spelling. The Calling a Format page covers the per-item contract.

Read the error code in code

import json, os, urllib.error, urllib.request

req = urllib.request.Request(
    "https://api.sume.com/v1/formats/your-handle/product-promo/bulk-runs",
    data=json.dumps({"concurrency": 1, "items": [{"instruction": "test"}]}).encode(),
    method="POST",
    headers={
        "Authorization": "Bearer " + os.environ["SUME_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": "scope-check-1",
    },
)
try:
    urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
    err = json.load(e).get("error", {})
    print(e.code, err.get("code"), err.get("details"))

Sources

Related posts

More in Formats

All Formats posts

Written by Sume