Render cron job that submits a Sume job: one key per slot
Render delays a cron run while one is active, and a manual trigger cancels it. Use a UTC slot Idempotency-Key so a re-run never bills a Sume job twice.

On Render, make the cron job submit one Sume job in webhook mode and derive the Idempotency-Key from the schedule slot (the UTC hour or day), not from a random value. Render can re-run or cancel a run, and a slot key makes the second submit return the first job instead of billing again.
What Render's cron runner does
Render documents guarantees that shape the key design. The table is from the vendor page (read 2026-10-10).
| Behavior | Render says | What it means for a Sume submit |
|---|---|---|
| Active runs | At most one run of a cron job is active at a time; a due run is delayed until the active one finishes | A slow run does not overlap, but the delayed run still fires later |
| Manual trigger | A manual trigger cancels any active run | A cancel can land after you submitted but before you logged the job id |
| Time zone | All day and time ranges use UTC | Build the slot from UTC |
| Max duration | Render stops an active run after 12 hours | Submit and exit; never wait for a render inside the cron |
The script
Set SUME_API_KEY as a Render environment variable. The request body follows the Image 1.0 fields in the Image 1.0 docs (prompt, quality, aspect_ratio, mode, webhook_url). The slot is the UTC date, so a nightly job has one key per night.
import json, os, urllib.request
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
slot = now.strftime("%Y-%m-%d")
body = {
"prompt": "Soft daylight product shot on a linen cloth",
"quality": "low",
"aspect_ratio": "4:5",
"mode": "webhook",
"webhook_url": "https://example.com/hooks/sume",
}
req = urllib.request.Request(
"https://api.sume.com/v1/image-1.0/generate",
data=json.dumps(body).encode(),
headers={
"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": "nightly-hero-" + slot,
},
)
with urllib.request.urlopen(req, timeout=20) as r:
print(r.status, r.read().decode())Handle the cancel-and-rerun case
If a manual trigger cancels the run after the HTTP call left, the retry uses the same key and gets the original job back. If you change the prompt for the same slot, expect 409 idempotency_conflict; put the revision in the key (nightly-hero-2026-10-10-v2) instead of reusing it.
- Key = purpose + UTC slot, never a timestamp or UUID made at run time.
- Exit after the 2xx response and let the webhook carry the result.
- On 429 or 503 retry with the same key; on 4xx validation errors stop.
Why a webhook and a slot key together
Submit in webhook mode so the scheduled process can exit. Sume sends only terminal events (job.completed, job.failed, job.canceled) and retries up to 10 attempts, 30 seconds apart, with a 10 second timeout for each attempt, per the Webhooks page. Use job_id as the idempotency key on your receiver.
Delivery is an optimization, not the only recovery path. Keep GET /v1/jobs/:id/status polls available for events that never arrive. A repeat of the same key with the same body is an exact retry. A repeat with a different body returns 409 idempotency_conflict, as the Generation admission page lists.
Sources
Related posts
More in Developers
- Retry or not: a decision table for failed Sume submit calls
Which Sume errors deserve a retry with the same Idempotency-Key, which mean poll the job, and which mean fix the request. One table and a 15-line classifier.
- Revoked a Sume API key and it still works? Up to 15 seconds
After you revoke a Sume API key, the API can keep accepting it for up to 15 seconds by default, because the key lookup is cached. What that means for a leak.
- Ruby verifier for Sume avatar job webhooks (HMAC SHA 256)
A Ruby method that verifies Sume's x-sume-webhook-signature: HMAC SHA 256 over timestamp.body, any sume-v1 entry, five-minute window, empty secret refused.
- Slow down a TTS voiceover: speed 0.6 to 1.5, volume, emotion
Sume TTS accepts generation_config with speed 0.6 to 1.5, volume 0.5 to 2 and a free-text emotion guide. How to retime a voiceover to a video.
Written by Sume