Exchange a Steam Web API auth ticket for application tokens.
const url = 'https://native-api.sudomimus.com/direct-issue/steam-ticket';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"applicationAnchor":"example","steamTicketHex":"example","steamAppId":1,"agreementAcceptance":{"revision":1,"locale":"en-US","contentSha256":"example","confirmed":true}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://native-api.sudomimus.com/direct-issue/steam-ticket \ --header 'Content-Type: application/json' \ --data '{ "applicationAnchor": "example", "steamTicketHex": "example", "steamAppId": 1, "agreementAcceptance": { "revision": 1, "locale": "en-US", "contentSha256": "example", "confirmed": true } }'The client SDK calls ISteamUser::GetAuthTicketForWebApi("sudomimus")
(the identity string MUST be exactly "sudomimus"), waits for the
GetTicketForWebApiResponse_t callback, hex-encodes the returned bytes,
and submits them with the application anchor and Steam App ID. The
ticket must satisfy the application’s configured rules and is
single-use for this exchange. Verify the returned tokens through the
application’s Session JWKS. If the account has not accepted the current
basic terms, the response includes the exact bilingual text and hashes.
Render one locale in the native client and obtain a separate affirmative
confirmation. Acquire a fresh Steam ticket and retry with
agreementAcceptance bound to the displayed revision, locale, and hash.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Public anchor identifying the integrating application.
Hex-encoded Steam Web API auth ticket bytes returned from
ISteamUser::GetAuthTicketForWebApi("sudomimus"). Hexadecimal
characters are case-insensitive.
Steam App ID under which the ticket was generated. Must be
allow-listed by the application’s STEAM_TICKET authentication
rule. Steam binds tickets to their issuing App ID; passing a
different value fails verification.
Present only after the native client displayed the complete
versioned basic terms and received an affirmative confirmation.
A prior LegalAgreementRequired response supplies the text and
digest. Use a new Steam ticket for this retry.
object
Responses
Section titled “Responses”Tokens issued.
object
Per-claim view across the five shareable claims, carried on both the 200 (why is a claim absent from the minted token) and the claim-gate 403 (what is still owed).
object
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
Short-lived access token (JWT). Payload sub is the pairwise
sector subject, sid identifies the session, and
jti identifies this token instance. It contains no profile claims
or raw account identifier; use Session API /userinfo for current
shared identity data.
Long-lived refresh token JWT with stable payload sid, version identifier jti, and positive rotationVersion. It contains no user identifier. Use Session API /refresh to obtain a new access token without re-acquiring a Steam ticket.
Example
{ "claims": { "email": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "firstName": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "lastName": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "staticAvatar": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "animatedAvatar": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" } }}Headers
Section titled “Headers”Prevent storage of the credential-bearing response.
Legacy cache instruction retained for credential responses.
Malformed request (e.g. invalid steamAppId).
Error response body. Known failures may include a stable reason.
Some failures are status-only and have an empty body. A missing,
malformed, or structurally invalid JSON body returns InvalidBody.
object
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}Steam rejected the ticket.
Error response body. Known failures may include a stable reason.
Some failures are status-only and have an empty body. A missing,
malformed, or structurally invalid JSON body returns InvalidBody.
object
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}The attempt was refused. The response reason distinguishes:
Layer1Denied,Layer2Denied,Layer3Denied— application policy rejected the attempt.ApplicationNotActive— the application is unavailable.AccountDisabledorAccountDeleted— the account is unavailable for issuance.EmailDomainBlocked,EmailDomainRequiresSso, orSsoAuthorityConflict— email-domain policy prevents issuance.ClaimConsentRequiredorRequiredClaimDataMissing— browser interaction is required before direct issuance can continue.LegalAgreementRequired— the native client must display and confirm the exact basic terms before retrying.
Claim-gate responses also include claims and an errand browser
handoff. Open errand.url, wait or poll its status, then acquire a
fresh Steam ticket and retry once after completion.
403 body. For the claim-gate reasons (ClaimConsentRequired,
RequiredClaimDataMissing) the claims view and the errand
handoff are present. For LegalAgreementRequired, agreement contains
the complete versioned basic terms for Steam native presentation, or
termsUrl identifies the version to accept during browser sign-in for
provisioned AccessKey and PublicKey credentials.
object
Stable machine-readable reason code.
Per-claim view across the five shareable claims, carried on both the 200 (why is a claim absent from the minted token) and the claim-gate 403 (what is still owed).
object
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC_ONLY always
emits the generated placeholder and never asks for real data.
SYNTHETIC_FALLBACK guarantees the claim is present but uses a
generated placeholder (a stand-in name, a proxy email, or a
generated avatar) when the user has not shared real data. Unlike REQUIRED, neither
synthetic mode blocks issuance or raises an errand.
The browser side-trip that unblocks a claim-gated direct-issue: a short-lived, single-use bearer URL where the user authenticates when required, completes missing data, and manages consent. Open the URL and let the browser page guide the user.
object
Bearer key (ernd_…); also the status-poll path key.
Open this in the user’s system browser.
object
object
object
object
object
object
object
object
object
object
Example
{ "claims": { "email": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "firstName": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "lastName": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "staticAvatar": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" }, "animatedAvatar": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" } }, "agreement": { "documentType": "BASIC_TERMS", "locales": { "en-US": { "document": { "schemaVersion": 1 } }, "zh-CN": { "document": { "schemaVersion": 1 } } } }}Headers
Section titled “Headers”Prevent storage of the credential-bearing response.
Legacy cache instruction retained for credential responses.
Application anchor not found.
Error response body. Known failures may include a stable reason.
Some failures are status-only and have an empty body. A missing,
malformed, or structurally invalid JSON body returns InvalidBody.
object
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}Conflict. The response reason distinguishes:
ReplayProtectionAlreadySeen— the ticket was already submitted or is being processed.AuthorizationArtifactStale— identity authority changed during the attempt.LegalAgreementRevisionMismatch— the submitted terms revision, locale, or hash no longer matches the server’s current text.
Acquire a fresh ticket before retrying either condition.
Error response body. Known failures may include a stable reason.
Some failures are status-only and have an empty body. A missing,
malformed, or structurally invalid JSON body returns InvalidBody.
object
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}Too many Steam-ticket attempts. Back off before acquiring and submitting another ticket.
Steam ticket verification is temporarily unavailable.
Error response body. Known failures may include a stable reason.
Some failures are status-only and have an empty body. A missing,
malformed, or structurally invalid JSON body returns InvalidBody.
object
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}default
Section titled “default”Error response.
Error response body. Known failures may include a stable reason.
Some failures are status-only and have an empty body. A missing,
malformed, or structurally invalid JSON body returns InvalidBody.
object
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}