Agent Completions webhook payload null: fetch result_url (1 MiB)
A Sume agent.run webhook over 1 MiB arrives with payload null and an error carrying result_url, while status still says OK. Verify, then fetch the receipt.

If your Agent Completions webhook shows payload: null, the run did not fail. Sume does not deliver a receipt larger than 1 MiB inline. It sends the envelope with payload set to null and an error object whose code is payload_too_large and which carries a result_url. The envelope status still reports the real outcome, so a successful run that was too big to ship is still OK. This is from Sume's run webhooks documentation, read on 2026-10-04.
What does the envelope contain?
| Field | On an oversized delivery |
|---|---|
event | agent.run.terminal |
status / outcome | the real result, such as OK and ok |
payload | null |
error.code | payload_too_large |
error.result_url | where to fetch the receipt |
request_id | the run id, stable across retries |
How should the handler work?
Verify the signature on the raw body first. Sume signs HMAC-SHA256 over the timestamp, a dot, and the raw body, and sends x-sume-webhook-timestamp and x-sume-webhook-signature as sume-v1=<hex>. Reject timestamps outside a window; five minutes is the suggested default. Then record the event and answer 2xx quickly, since each attempt has a 10-second timeout and up to 10 attempts are made. Dedupe on request_id.
After the check, branch on payload. When it is null and the code is payload_too_large, fetch the receipt from result_url with an API key that has agent_completions:read.
import hashlib, hmac, time
def verify(raw: bytes, ts: str, sig: str, secret: str) -> bool:
if not secret:
raise ValueError('empty webhook secret')
if abs(time.time() - int(ts)) > 300:
return False
mac = hmac.new(secret.encode(), ts.encode() + b'.' + raw, hashlib.sha256)
return hmac.compare_digest('sume-v1=' + mac.hexdigest(), sig)
def receipt_url(event: dict):
if event.get('payload') is None:
err = event.get('error') or {}
if err.get('code') == 'payload_too_large':
return err['result_url']
return NoneWhere do I get the secret?
The signing secret is on the Webhooks tab of the dashboard, or from GET /v1/webhooks/signing-secret with a key that has account:read. Sume derives it for your workspace, and a different workspace's secret cannot verify your delivery. The verifier above refuses an empty secret on purpose, so a missing environment variable fails loudly instead of accepting everything.
What if delivery fails?
A failed delivery does not change the run. After ten rejected attempts the delivery is exhausted, and the run stays complete. Fetch it from result_url, as the Run webhooks page says, or poll the status_url. A run starts with POST /v1/agent/completions, which needs generation_spend_cap_usd; see Agent Completions. Use the Jobs and results page for generation-job events, which are a separate surface.
What should I log?
Log the request_id, the outcome, and whether payload was null. Do not log the signing secret or the raw body in full, because a run receipt can carry long text. When the body is oversized, the receipt is still waiting at result_url, so a log line with the run id is enough to find it again. Keep the handler fast: record, answer 2xx, and fetch afterwards.
Sources
Related posts
More in Agents
- AI video agent vs a single-model video generator: what you call
A single-model generator returns one clip from a prompt. An agent plans shots, calls tools and assembles a video. How the Sume calls differ.
- @-mention an agent on a video asset: Runway vs Sume
Runway Enterprise lets you @-mention its Agent in asset comments. Sume Agents take work via the Agent Completions API; media jobs report by webhook.
- Re-render Sora prompts from an agent: jobs_wait takes 20 ids
An agent re-rendering saved Sora prompts should wait on up to 20 Sume job ids per call, read results in one batch, and not resubmit after a wait slice expires.
- Cap a voiceover batch at $1: tts_create dry_run and max_spend_usd
Preview what a Sume TTS call will cost before it runs, and cap the spend. How dry_run and max_spend_usd work on tts_create, with a 20-line cost example.
Written by Sume