SimTX API/Game tickets
A game ticket is a short-lived, single-use credential that a client presents to a game server in the ClientHello. Tickets keep reusable credentials away from game servers: the server only ever sees a ticket that is worthless sixty seconds later. A ticket can also be bound to a station, which is how a receiver or transmitter session gets the right to use one of the account's persistent stations.
Anonymous ad-hoc receivers and anonymous control connections do not need a ticket.
Request
POST /api/v1/game-tickets
Requires a bearer credential. Rate limit: 120 requests per minute per IP address.
{
"serverId": "argon",
"role": "tx-audio",
"stationId": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"antennaId": "9b2c1e47-2f0a-4c55-8d1e-6a7b8c9d0e1f"
}
| Field | Type | Required | Description |
|---|---|---|---|
serverId |
string | Yes | A serverId from the server directory.
|
role |
string | Yes | The protocol role the ticket will be used for. See Roles. |
stationId |
string (UUID) | No | Bind the ticket to a persistent station. Transmitter roles need a station the account owns; receiver also accepts another account's PUBLIC station.
|
antennaId |
string (UUID) | No | The station's antenna. Default: its first antenna by ordinal. |
rigId |
string (UUID) | No | The station's rig. Default: its first rig by ordinal, or none when the station has no rigs. |
Roles
The ticket is bound to one role. The role string in the request must correspond to the role sent in the hello.
Ticket role |
Hello role |
Permission required to obtain the ticket | Station binding |
|---|---|---|---|
receiver |
ROLE_RECEIVER (1) |
None | Optional |
tx-audio |
ROLE_TX_AUDIO (2) |
game.transmit |
Optional; transmitting through a station needs it |
tx-generated |
ROLE_TX_GENERATED (3) |
game.transmit |
Optional; transmitting through a station needs it |
control |
ROLE_CONTROL (4) |
catalog.publish |
Not allowed |
moderation |
ROLE_MODERATION (5) |
moderation.manage |
Not allowed |
An authenticated control connection is only needed to publish to or delete from the extension catalog and to monitor one's own transmitters. Reading the station list, maps, ephemerides, passes and the catalog works anonymously.
The permission check uses the intersection of the credential's scopes and the account's effective permissions on that server. A credential created with scope catalog.publish cannot obtain a tx-audio ticket, even if the account itself may transmit.
Response
201 Created:
{
"ticket": "stx_gt1_7e21...",
"expiresAt": "2026-10-24T12:01:00Z",
"station": {
"stationId": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"antennaId": "9b2c1e47-2f0a-4c55-8d1e-6a7b8c9d0e1f",
"rigId": "c41d7a52-0e3b-4f6a-9c8d-1b2a3c4d5e6f",
"revision": 7,
"access": "OWNER"
}
}
| Field | Type | Description |
|---|---|---|
ticket |
string | The ticket. Place it in ClientHello.credential with auth = AUTH_KIND_GAME_TICKET.
|
expiresAt |
string | Expiry time, 60 seconds after issue. |
station |
object | Only for station-bound tickets: what was bound. |
station.stationId |
string | The station. |
station.antennaId |
string | The bound antenna, also when the request named none. |
station.rigId |
string | The bound rig. Omitted when none is bound. |
station.revision |
integer | The station's revision when the ticket was minted. |
station.access |
string | OWNER (transmit and receive) or LISTENER (receive only, on another account's PUBLIC station).
|
Station-bound sessions
A session started with a station-bound ticket must send a StationBinding for the same station, antenna and rig in its ReceiverStart or TransmitterStart. Copy the ids from the station object; an empty antenna or rig id in the binding accepts the part the ticket bound. A binding that does not match, or an ad-hoc site sent with a station-bound ticket, is refused with ERROR_CODE_FORBIDDEN. See Binding a session.
The station snapshot the game server uses is taken when the ticket is consumed. A ticket minted for a station without rigs gets the station's first rig if one was added before the ticket was used.
Rules
- A ticket is valid for 60 seconds and can be used once.
- It is bound to the requested
serverIdandrole, and to the station if one was given. Presenting it to another server or with another role fails withHELLO_STATUS_CREDENTIAL_INVALID. - Fetch a new ticket for every connection, including every reconnect. Do not fetch tickets in advance.
- Station-bound tickets are issued only for servers whose every live node advertises the feature
stations.v1. - A ticket does not carry the user's identity in readable form. The server resolves it and returns the account in the ServerHello.
Errors
| HTTP | code |
Cause |
|---|---|---|
| 400 | ticket_request_invalid |
The message distinguishes: serverId and role are required; unknown protocol role; unknown, disabled, or offline server; credential is not authorized for the requested protocol role (the credential's scopes or the account's permissions lack the role's permission). With station fields: antennaId and rigId need a stationId; station binding is only available for transmitter and receiver roles.
|
| 404 | station_not_found |
Unknown station. |
| 403 | station_forbidden |
A transmitter role on a station the account does not own, or receiver on another account's UNLISTED station.
|
| 409 | station_inactive |
The station is deleted or deorbited. |
| 409 | station_binding_unsupported |
A live node of that server lacks the feature stations.v1.
|
| 400 | antenna_not_found, rig_not_found |
The antenna or rig does not belong to the station. |
401 credential_missing and 401 credential_invalid apply as for every authenticated endpoint.
Example
curl -s -X POST https://auth.simtx.net/api/v1/game-tickets \
-H "Authorization: Bearer $SIMTX_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"serverId":"argon","role":"receiver","stationId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}'