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.
- AgentCore payments GA vs Sume's API key and credit balance
AWS made AgentCore payments GA on Aug 18, 2026 with x402 upto and MPP. Sume uses an API key or OAuth with a credit balance and per-call spend caps instead.
Written by Sume