OpenAI Python 3.23 turn artifacts: hand over a Sume render

OpenAI Python SDK 3.23.0 adds file staging and turn artifact downloads for agents. Sume job webhooks give you a public media.sume.com URL to hand over.

4 min readSume
All posts

To give an OpenAI agent a Sume render, pass it the artifact URL from the finished job: Sume copies generated output to a public media.sume.com URL, and the job webhook payload carries it in artifacts[].url. The OpenAI side is the part that changed: the release notes list Python SDK v3.23.0 (Oct 1, 2026) with "session traces and Realtime translations", and say agents can stage files and download turn artifacts.

What the release notes say

I am not describing the exact OpenAI method names here, because the release page lists the capability and not the call signatures. Use the SDK reference for those.

OpenAI Python SDK 3.23.0 (read 2026-10-03)
ItemDetail
Release dateOct 1, 2026
HeadlineSession traces and Realtime translations
AgentsCan stage files and download turn artifacts

Where the Sume side comes from

A Sume generation job reaches a terminal state and, if you submitted with mode webhook and a webhook_url, Sume POSTs a signed job.completed event. The payload holds an artifacts array; each entry has an id, a url on media.sume.com, a type and a content type. Treat the URL as opaque, store the Sume URL and not a provider URL, and use job_id as your idempotency key.

The script below verifies the signature over the timestamp, a dot and the raw body, refuses an empty secret, and returns the artifact URLs. It runs as written; it signs a sample body itself so you can see a pass and a fail.

import hashlib, hmac, json, time

def verify(raw: bytes, ts: str, header: str, secret: str, tol=300) -> bool:
    if not secret:
        raise ValueError('empty webhook secret')
    if abs(int(time.time()) - int(ts)) > tol:
        return False
    digest = hmac.new(secret.encode(), f'{ts}.'.encode() + raw, hashlib.sha256).hexdigest()
    want = f'sume-v1={digest}'
    ok = False
    for entry in header.split(','):
        ok |= hmac.compare_digest(entry.strip(), want)
    return ok

def artifact_urls(raw: bytes) -> list[str]:
    body = json.loads(raw)
    if body.get('event') != 'job.completed':
        return []
    return [a['url'] for a in body['payload']['artifacts']]

if __name__ == '__main__':
    secret = 'test-secret'
    raw = json.dumps({'event': 'job.completed', 'job_id': 'job_1', 'payload': {'artifacts': [
        {'id': 'artf_1', 'url': 'https://media.sume.com/artifacts/x.mp4', 'type': 'video'}]}}).encode()
    ts = str(int(time.time()))
    sig = 'sume-v1=' + hmac.new(secret.encode(), f'{ts}.'.encode() + raw, hashlib.sha256).hexdigest()
    print(verify(raw, ts, sig, secret), artifact_urls(raw))
    print(verify(raw, ts, 'sume-v1=bad', secret))

Hand it to the agent

Once you have the URL, give it to the agent as the file it should work from, using whichever staging call the SDK documents. If your agent must read the file, a public HTTPS URL is simpler than a local path. Keep status_url polling in place for deliveries that never arrive.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume