Webflow CMS item webhook to Sume: ack first, three retries, one image
Webflow retries a failed webhook 3 times, 10 minutes apart, then deactivates it. Ack with 200, key the Sume job by item id, and check the signature timestamp.

When a CMS item is created in Webflow, the collection_item_created webhook can start a Sume image job. Answer 200 quickly, key the Sume request by the item id, and skip draft items. Webflow retries a failed delivery 3 times at 10-minute intervals and deactivates a webhook that keeps failing, so a handler that blocks on generation can end up switching itself off.
This post gives the Sume side. Webflow's page describes signed requests, but write your verifier from that page and test it against a real delivery; the code below starts after verification.
What Webflow says about delivery
The webhook guide describes two headers, x-webflow-timestamp and x-webflow-signature, with the signed string built from the timestamp, a colon and the JSON body, and tells you to reject timestamps older than 5 minutes. It expects a 200 response, retries up to 3 times 10 minutes apart, and deactivates a webhook after repeated failures. A site can register up to 75 webhooks per trigger type.
The collection_item_created payload includes the item id, cmsLocaleId, fieldData with at least name and slug, and isDraft. That is all the Sume prompt needs: the name for the subject, and isDraft to avoid paying for images on items nobody will publish. When the editor later publishes the item, you can submit then, using the same key, and an earlier submit would simply be adopted.
| Webflow rule | Value | Handler decision |
|---|---|---|
| Expected response | 200 | Return it before slow work |
| Retries | 3, 10 minutes apart | Stable key from the item id |
| After repeated failure | Webhook deactivated | Do not return 5xx for permanent errors |
| Replay window | Reject timestamps older than 5 minutes | Check the timestamp header |
| Draft items | isDraft true in payload | Skip, or wait for publish |
Submitting from the payload
Pass the payload object from the verified webhook body. A 202 or a replay both count as success.
import os, requests
def submit_item_image(payload: dict) -> int:
if payload.get("isDraft"):
return 200
name = (payload.get("fieldData") or {}).get("name", "")
if not name:
return 200
try:
r = requests.post(
"https://api.sume.com/v1/images",
headers={"Authorization": f"Bearer {os.environ['SUME_API_KEY']}",
"Idempotency-Key": f"webflow-item-{payload['id']}"},
json={"model": "sume/auto", "mode": "async",
"prompt": f"Header illustration for a post titled: {name}"},
timeout=15,
)
except requests.RequestException:
return 503
return 503 if r.status_code == 429 or r.status_code >= 500 else 200Why the slow path is separate
Webflow's 10-minute spacing gives you a long gap between attempts, which is good for a transient Sume outage and bad for a handler that hangs. Return 200 from the web request as soon as the job is submitted, and collect the finished image through the Sume job webhook. Writing it back to the CMS item is then an independent step with its own retries.
Sources
Related posts
More in Integrations
- Wix Stores product video: 50 MB limit and an AI clip
Wix Stores takes AVI, MP4, MOV or MPEG product video up to 50 MB. Measure a Sume clip, then shorten it, drop audio or conform its size with video trim.
- How to add an MCP server to ChatGPT with developer mode
Turn on ChatGPT developer mode, create an app for the server's URL, and sign in with OAuth. The steps, with Sume's hosted MCP server as the example.
- How to add subtitles to a video in Python
Add subtitles to a video in Python with Requests: POST the video URL to Sume's /v1/video-captions, poll the job, then read the captioned video_url.
- Add Sume to Claude as a custom connector (remote MCP)
Add Sume's hosted MCP server to Claude under Customize > Connectors, see what Sume's OAuth consent grants, and decide whether to allow paid tools.
Written by Sume