A lost response on a 30 s Kling motion control submit: reuse the key
If a network timeout hides the reply to a 30-second Kling motion control submit, a new Idempotency-Key reserves $4.725 again. Reuse the key. Python retry loop.

When the reply to a Kling 3.0 Motion Control submit is lost to a timeout, you do not know whether Sume admitted the job. Retry with the same Idempotency-Key, and the retry returns the original job instead of billing a second one. Retry with a new key, and a 30-second reference reserves $4.725 a second time, for $9.45 in total.
Sume's jobs documentation states the rule directly: retry the submit itself with the same key, and do not submit a new paid job for the same intent.
What a new key costs
Each admitted job reserves ceil(duration_seconds) times $0.1575. Two admitted jobs are two reservations, and both are captured if both complete.
| Reference seconds | One job | Retry with a new key | Extra cost |
|---|---|---|---|
| 8 | $1.26 | $2.52 | $1.26 |
| 15 | $2.3625 | $4.725 | $2.3625 |
| 30 | $4.725 | $9.45 | $4.725 |
Choose the key before the first send
Make the key from the intent, not from the attempt. A key that includes a random value or a clock reading is a new key on every retry, which defeats the purpose. Use the shot id, or a hash of the still URL, the motion URL, and the duration.
- Same still, same motion video, same duration: same key.
- A changed still or a changed motion video is a new intent: new key.
- Keep the key in your own store with the job id once you have it.
A retry loop
This loop sends the same key on each attempt and stops on any HTTP answer, since an HTTP answer means Sume saw the request. It retries only when no answer arrived.
import json
import os
import time
import urllib.error
import urllib.request
URL = 'https://api.sume.com/v1/kling/3.0/motion-control'
def submit(body, key, attempts=3):
data = json.dumps(body).encode()
headers = {
'Authorization': 'Bearer ' + os.environ['SUME_API_KEY'],
'Content-Type': 'application/json',
'Idempotency-Key': key,
}
for attempt in range(attempts):
req = urllib.request.Request(URL, data, headers)
try:
with urllib.request.urlopen(req, timeout=20) as res:
return json.load(res)
except urllib.error.HTTPError as err:
return {'http_status': err.code}
except (urllib.error.URLError, TimeoutError):
time.sleep(2 ** attempt)
raise RuntimeError('no response; reuse the same key later: ' + key)If you give up
If every attempt fails, do not mint a new key to try again. Wait, then call the same submit with the same key, or list your recent jobs and look for one with your metadata before you decide a job was never created. The wider rules, with a per-shot pattern, are in idempotency keys for AI video APIs.
Sources
Related posts
More in Developers
- Use your ad variant id as the Idempotency-Key on Sume
Name each ad variant once and send that name as the Idempotency-Key. Retries do not double-bill, and the receipt echoes it back so results map to your ad names.
- Add an object to a set spot in a photo: box to words in Python
Sume has no bounding-box field. Turn a 0-1000 box into placement words for an Ideogram 4.5 edit, and into pixels for a mask, with a short Python helper.
- After imagen-4.0-generate-001: read n from endpoints, use webhook mode
Do not assume your old image count carries over. Read supported_parameters.n from the Sume endpoints route, then submit in webhook mode and wait for.
- Alt text for a 30-image gallery in one Sume Agent Completion
One Agent Completion call can take up to 30 images and return an alts array under an object schema. Python stdlib script with the cap, poll and limits.
Written by Sume