Svix App Portal MCP and SDK v2: debugging Sume webhook deliveries
Svix now ships an App Portal MCP server for coding agents. For Sume webhooks, debug with the signature check, a test delivery and redeliver endpoints.

If you use Svix to receive or forward webhooks and let a coding agent debug them through the new App Portal MCP server, keep Sume's own checks next to it: verify the HMAC signature, send a test delivery, and redeliver a missed event. Svix's September 2026 changelog lists SDK v2 (where update becomes upsert), a CLI wizard and the App Portal MCP server. Sume's webhook behaviour is documented separately.
What Svix announced
| Item | Detail |
|---|---|
| SDK v2 | Update becomes upsert |
| CLI wizard | New |
| App Portal MCP server | Lets coding agents debug webhooks |
Sume's side of the debugging loop
Start with the signature. Sume signs <timestamp>.<raw_body> with HMAC-SHA256 and sends x-sume-webhook-timestamp, x-sume-webhook-signature as sume-v1=<hex>, and x-sume-webhook-secret-fingerprint. The default replay window is 300 seconds. The fingerprint tells you which secret signed the delivery, useful during the 24 hour rotation window when the signature header carries several entries.
import hashlib
import hmac
import os
import time
def verify(raw: bytes, ts: str, sig_header: str, secret: str) -> bool:
if not secret:
raise ValueError("signing secret is empty")
if abs(time.time() - int(ts)) > 300:
return False
mac = hmac.new(secret.encode(), ts.encode() + b"." + raw, hashlib.sha256)
want = "sume-v1=" + mac.hexdigest()
return any(hmac.compare_digest(p.strip(), want) for p in sig_header.split(","))
if __name__ == "__main__":
secret = os.environ.get("SUME_COM_WEBHOOK_SIGNING_SECRET", "")
body = b'{"ok":true}'
ts = str(int(time.time()))
sig = "sume-v1=" + hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
print(verify(body, ts, sig, secret))
Test and replay
Use POST /v1/webhooks/test-deliveries to send a test event, then POST /v1/jobs/{id}/webhook/redeliver (needs jobs:write) or POST /v1/format-runs/{id}/webhook/redeliver (needs formats:write) to replay a real one. Dedupe on job_id for jobs, run_id or request_id for runs, since Sume retries up to 10 times with a 10 second timeout per attempt.
- The URL must be public HTTPS; redirects are not followed.
- A receipt over 1 MiB arrives as
payload: nullwithpayload_too_large; fetchresult_url. - Canceled and skipped runs send no webhook.
Keep secrets away from the agent
An agent debugging through MCP should see delivery metadata, not the signing secret. Read the secret with GET /v1/webhooks/signing-secret (account:read) only in the service that verifies. Rotating is POST /v1/webhooks/signing-secret/rotate; do not let an automated debug session do it. Polling remains the backup if deliveries are lost.
Sources
Related posts
More in Integrations
- Telegram sendAnimation: H.264 without sound, 50 MB, how to trim one
sendAnimation takes a GIF or H.264/MPEG-4 clip without sound, up to 50 MB. Cut a short silent loop from a generated video with Sume video-trim audio drop.
- sendAnimation or sendVideo for a short AI clip: which Telegram method
Pick sendAnimation for a silent looping clip, sendVideo for sound or a poster cover. How the Bot API methods differ and how Sume video-trim preps both.
- Telegram sendMediaGroup: 2-10 items, building an AI image album
sendMediaGroup sends 2 to 10 photos or videos as one album. Batch-generate a matching set with the Sume images API and keep each file inside the photo limits.
- Telegram sendPhoto limits: 10 MB, 10000 px, 20:1 ratio
Telegram sendPhoto rejects photos over 10 MB, over 10000 px width plus height, or past 20:1. How to size an AI image with Sume before the bot sends it.
Written by Sume