fal webhook status OK or ERROR vs the Sume job webhook
fal posts a webhook with status OK or ERROR, separate from queue status. Sume's job webhook uses the same words plus an event name. One handler for both.

fal's webhook payload carries a status of OK or ERROR, and Sume's job webhook payload does too, but they sit in different places in the lifecycle. On fal, OK/ERROR is a webhook-only outcome, distinct from the queue statuses IN_QUEUE, IN_PROGRESS and COMPLETED. On Sume, status: "OK" rides next to an event name (job.completed, job.failed, job.canceled) and the job's own status stays completed, failed or canceled.
If you are porting a fal handler, the field name matches but you should branch on event, not only on status.
What does fal's webhook say?
Per the fal queue page, passing webhook_url to submit() makes fal post the result automatically on completion. The page says the webhook body has status "OK" for success or "ERROR" for failure, and that this is distinct from the three request lifecycle states. This page does not describe signature verification, which is covered separately by fal's other docs and by our fal signature comparison.
What does Sume's job webhook look like?
Sume sends terminal job events only: no progress or partial deliveries. Submit with mode: "webhook" and a public HTTPS webhook_url (callback_url is an alias, and sending either without a mode gives you webhook mode). The envelope carries event, request_id, job_id, status and payload.artifacts[], and two rules follow from it:
- The asymmetry that matters: on Sume a canceled job also arrives with
status: "ERROR". - If your fal code treats
ERRORas a failure to alert on, canceled Sume jobs will page you. Branch oneventfirst.
| Question | fal | Sume |
|---|---|---|
| Outcome field | status: OK or ERROR | status: OK; failed and canceled use ERROR with an error object |
| Event name | Not described on the queue page | job.completed, job.failed, job.canceled |
| Job status vocabulary | IN_QUEUE, IN_PROGRESS, COMPLETED | queued, processing, completed, failed, canceled |
| Progress events | Not described on the queue page | None, terminal events only |
| Result location | Result stored, retrievable from the result URL | payload.artifacts[] with media URLs |
How do I write one handler that reads both?
Keep the verification step provider specific and normalize after it. This Python function refuses an empty secret and checks the Sume signature (sume-v1= HMAC SHA 256 over timestamp.raw_body, five minute tolerance as the docs suggest), then maps the event to your own state.
import hashlib, hmac, json, time
def verify_sume(raw: bytes, ts: str, header: str, secret: str) -> bool:
if not secret:
return False
try:
t = int(ts)
except ValueError:
return False
if abs(time.time() - t) > 300:
return False
mac = hmac.new(secret.encode(), ts.encode() + b"." + raw, hashlib.sha256)
want = "sume-v1=" + mac.hexdigest()
return any(hmac.compare_digest(want, e.strip()) for e in header.split(","))
def normalize(raw: bytes) -> str:
body = json.loads(raw)
return {"job.completed": "done", "job.failed": "failed",
"job.canceled": "canceled"}.get(body.get("event"), "ignore")What should I keep as a fallback?
Sume's docs recommend keeping a polling path alongside webhooks: GET /v1/jobs/{id}/status until terminal: true, then GET /v1/jobs/{id}/result. During a signing-secret rotation the signature header carries one sume-v1= entry per live secret, newest first, which the loop above handles with any.
Sume also exposes x-sume-webhook-secret-fingerprint on every delivery so you can compare it with the dashboard when a signature fails, without sending the secret anywhere. Read the delivery details in Sume webhooks, and the broader differences in Sume vs fal.
Sources
Related posts
More in Comparisons
- FFmpeg whisper filter vs a hosted transcript call for video
FFmpeg's whisper filter needs whisper.cpp and a model file you manage. Sume's video-inspect transcribe returns words and sentence segments for $0.01 a minute.
- FFmpeg xfade has 59 transitions: which does Sume Timeline take?
FFmpeg's xfade page lists 59 transition values, including custom. Sume Timeline 1.0 accepts six: fade, wipeleft, wiperight, slideup, slidedown and dissolve.
- FLUX 3 Image reference size: 256 px to 16 MP, and Sume URL rules
BFL says each FLUX 3 Image reference is 256x256 px to 16 MP, 1 to 10 images. Sume lists FLUX.2 ids; its reference rules are public HTTPS and a catalog count.
- FLUX 3 or Ideogram 4.5 for ad text: what is known, and a test
Higgsfield lists both models with text-related claims. Here is exactly what its changelog says, what Sume lists today, and a test plan that settles it for you.
Written by Sume