Python 3.14.8 urllib credential fix: a stdlib Sume job poll script
Python 3.14.8 fixed urllib HTTPPasswordMgr handing credentials across schemes. Upgrade, and call Sume with an x-api-key header from a plain stdlib script.

Python 3.14.8 is an expedited security release published on September 30, and its notes list a fix for urllib HTTPPasswordMgr handling of credentials across schemes, alongside fixes for ssl, tarfile, zipfile and an Expat update to 2.8.5 (Python 3.14.8 release page, read 2026-10-04). If you run Python scripts that call the Sume API with only the standard library, upgrade to 3.14.8 on the 3.14 line. Then check that no password manager sits in the request path at all.
A Sume call should not involve one. The API takes the key in a header, either Authorization: Bearer ... or x-api-key: sume_live_..., and the API overview says to send one of them. Sending both is rejected with a 401. Because the key is a header and the base URL is always https://api.sume.com, there is no Basic auth realm for a password manager to match against.
What to check in an existing script
- Search for
HTTPPasswordMgr,HTTPBasicAuthHandlerandbuild_openerin code that talks to Sume. None should be needed. - Make sure the key never appears in the URL. Keep it in the header and read it from the environment.
- Pin the runtime in your container image or CI matrix so the patched release is the one that runs.
- Re-run your poll loop once after the upgrade, since the TLS and HTTP-adjacent fixes in a security release touch code your script uses.
A stdlib submit-and-poll script
The script below submits an image job with an Idempotency-Key, polls GET /v1/jobs/{id}/status until terminal is true, and prints the result when result_ready is true. It honours next_poll_after_seconds and never sleeps less than two seconds. It exits at once if the key is not set. The endpoints and the three-step flow come from the jobs and results guide.
import json, os, sys, time, urllib.request, uuid
KEY = os.environ.get("SUME_API_KEY", "")
if not KEY:
sys.exit("set SUME_API_KEY")
def call(method, path, body=None, extra=None):
headers = {"x-api-key": KEY, "content-type": "application/json", **(extra or {})}
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request("https://api.sume.com" + path, data=data,
method=method, headers=headers)
with urllib.request.urlopen(req, timeout=60) as res:
payload = json.load(res)
return payload.get("data", payload)
prompt = "Product hero shot of a matte black bottle on marble"
sub = call("POST", "/v1/image-1.0/generate", {"prompt": prompt, "mode": "async"},
{"Idempotency-Key": str(uuid.uuid4())})
job_id = sub["request_id"]
print("job", job_id)
while True:
st = call("GET", f"/v1/jobs/{job_id}/status")
if st.get("terminal"):
break
time.sleep(max(2, st.get("next_poll_after_seconds") or 2))
if st.get("result_ready"):
print(json.dumps(call("GET", f"/v1/jobs/{job_id}/result"), indent=2))
else:
print("ended without a result:", st.get("sume_status"))Handling errors without a library
urlopen raises HTTPError for any 4xx or 5xx, and the body of that error is still the JSON envelope with code, request_id and retryable. Read it with json.load(error) before you decide what to do. A 402 insufficient_credits should stop the script, and a 429 should wait for the server's retry_after_seconds before the same call goes out again with the same Idempotency-Key. A new key on a retry would create a second job and a second charge.
Sources
Related posts
More in Developers
- Railway webhook custom headers vs Sume's signed headers
Railway project webhooks now accept custom headers. Sume signs its callbacks with x-sume-webhook-timestamp and x-sume-webhook-signature; verify them in Python.
- Railway Sandboxes: run the Sume CLI with an env-var key
Inside a short-lived sandbox, install the Sume CLI with the hosted installer, pass SUME_API_KEY as an environment variable, and never print it.
- Recraft V4.1 Flash: median 1.3 s, p95 1.8 s. Set timeouts from p95
Recraft quotes a median of about 1.3 seconds and a p95 of 1.8 seconds for V4.1 Flash. How to turn latency claims into timeouts and polling for image APIs.
- Reproduce the same AI voiceover later: model id, voice, settings
To redo a narration line months later you need the model id, voice, language, format and settings. Sume's completed TTS job records them. A short routine.
Written by Sume