End-user id on jobs: OpenAI safety identifier vs Sume metadata
OpenAI's Realtime guide asks for an OpenAI-Safety-Identifier header. Sume stores caller metadata on the job but does not send it to the provider. Use both.

OpenAI's Realtime guide tells integrations to send an OpenAI-Safety-Identifier header. Sume's metadata field is different: it is caller metadata stored on the job, and the docs say it is not sent to the provider. Use the header for the provider's side and metadata for your own bookkeeping.
Neither is a substitute for the other, and neither should carry anything you would not want in a log.
Two different fields
From the OpenAI Realtime guide and Sume's Image and Music docs, read 2026-10-03.
| Field | Who receives it | Purpose in the docs |
|---|---|---|
OpenAI-Safety-Identifier header | OpenAI | Send on Realtime requests, per the guide |
metadata on a Sume job | Stored on the Sume job | Caller metadata; not sent to the provider |
| Value the guide specifies for the header | Not given in the entry reviewed | Read the guide for the format before you choose one |
Derive an opaque id
Do not put an email address, a name or a raw account id in either field. Derive a stable opaque id from your own user id with a keyed hash, and use that string wherever you need an end-user reference. The same user then maps to the same value across sessions without exposing who they are. The secret must be set, and the script refuses to run without it.
import hashlib, hmac, os
SECRET = os.environ.get("USER_TAG_SECRET", "")
if not SECRET:
raise SystemExit("USER_TAG_SECRET is not set")
def user_tag(user_id: str) -> str:
mac = hmac.new(SECRET.encode(), user_id.encode(), hashlib.sha256)
return "u_" + mac.hexdigest()[:32]
tag = user_tag("account-1234")
realtime_headers = {"OpenAI-Safety-Identifier": tag}
sume_body_extra = {"metadata": {"end_user": tag}}
print(realtime_headers, sume_body_extra)Where each goes
A short wiring list.
- Realtime session setup on your server: add the header to the request that opens the session.
- Sume job submit from the same server: add
metadatawith the same tag to the image or music request body. - When a job fails or a user reports an output, search your job records by the tag rather than by identity.
- Keep the secret out of the browser. A tag the page can compute is not opaque.
What not to assume
The Sume docs say metadata is stored and not forwarded, which means it will not help a provider attribute abuse to a user. If a provider asks for an identifier, send it in the provider's own field. And since the OpenAI entry reviewed gives the header name but not its value format, confirm the format on the guide before shipping.
Sources
Related posts
More in Developers
- Test a faster-and-cheaper claim with your own timings and usage.cost
Luma's news page says Ray3.14 is 4x faster and 3x cheaper. A short Python script turns your own job timings and usage.cost values into two ratios you can trust.
- Text to Dialogue continuity: 100-character context, 3 request IDs
ElevenLabs' Sept 28 changelog adds previous_text and future_text (100 chars max) and request-ID chaining (3 max). A Python limit check.
- VS Code 1.140 shared MCP config files: what goes in the Sume entry
VS Code 1.140 lets MCP servers live in portable config files shared across Copilot tools. For Sume the entry is one URL, and no key belongs in the file.
- What a media MCP server should declare at server/discover
MCP 2026-07-28 adds a required server/discover call. A media server has more to say than versions: async jobs, wait limits, scopes. Where Sume documents each.
Written by Sume