the station docs

The relay

The chain holds iron. The relay carries air: who is in a room, and what they say. It is at relay.the-station.xyz.

The relay is trusted with very little. Every line of speech carries its speaker's signature, and every client checks it. The relay can lose a line, or refuse to carry one. It cannot put words in anyone's mouth.

Signing

Every signature is ed25519, over the UTF-8 bytes of a short text, sent as base64. \n is a newline. <ts> is the time in milliseconds.

ForThe text that is signed
The hellohello\n<room>\n<ts>
Saying something<room>\n<ts>\n<msg>
A whisperwhisper\n<to>\n<ts>\n<msg>
Where you standhere\n<ts>\n<deck>,<x>,<y>
A telltell\n<to>\n<ts>\n<msg>

A hello must be less than two minutes old.

Entering a room

A room's id is its name. Open a socket to it with a signed hello in the address:

wss://relay.the-station.xyz/room/<room>/ws?pk=<key>&ts=<ts>&sig=<signature>

The relay checks the signature, and that the key is a citizen, before the room is woken.

Who is at the doorWhat happens
A lit keyThe socket opens
A ghost, at its own portThe socket opens. A port's id is the-iron-port--<key>.
A ghost, anywhere elseOne message, {"t":"err","port":true}, then the socket closes with code 4003
No signatureHTTP 426
A signature that does not checkHTTP 403
A room that does not existHTTP 404

Then say hello on the socket, and wait for commands before speaking:

{"t":"hello","pubkey":"<key>","ts":<ts>,"sig":"<signature>"}

Adding "from":"north" tells the room which door you came in by.

What you send

Message
{"t":"hello", pubkey, ts, sig}Once on entering, and again after paying a door
{"t":"say", room, pubkey, ts, msg, sig}Air
{"t":"whisper", to, pubkey, ts, msg, sig}To one key, in this room
{"t":"history", n}Ask for the last lines, up to 50
{"t":"leave", dir}Say which door you are leaving by
{"t":"ping"}Answered with {"t":"pong"}

What you receive

MessageWhen
{"t":"presence", count, who}On entering, and whenever someone comes or goes. who is a list of keys.
{"t":"scrollback", lines}After your hello is admitted: the last few lines
{"t":"commands", mask}After scrollback. The room's terminals: 1 jup, 2 klend, 4 hylo.
{"t":"say", room, pubkey, ts, msg, sig}Someone spoke
{"t":"whisper", from, to, ts, msg, sig}A whisper to you, or the echo of your own
{"t":"tell", from, to, ts, msg, sig}A word sent to you from another room
{"t":"enter", pubkey, dir} and exitSomeone used a door
{"t":"etch", pubkey, msg, sig}A line was carved here
{"t":"porthole", source, text, ts}Something crossed the glass
{"t":"door", kind, amount, period, mint}The door is kept and you are not a member
{"t":"depart", to}The shuttle is leaving the port: go to the room at to
{"t":"err", why}The relay refused something, and why

A line may carry as, delegation, seeker, skr and drunk. drunk is how many drinks the chain says are still in the speaker, 1 to 12, as the relay read it. When as is present, the speaker is the account as, and pubkey is a voice key that account has signed for. Check the delegation before believing it.

Verifying a line

Do not trust a say because the relay sent it. Check that sig is pubkey's signature over <room>\n<ts>\n<msg>. The Station's own clients drop any line that fails.

Voices

A wallet that asks before every signature would make talking tiresome. So an account may sign once for a voice key, and the voice key signs the speech.

The account signsvoice\n<voice key>\n<account>\n<expires>
expiresUnix seconds, at most seven days ahead
On the socket address&as=<account>&exp=<expires>&dsig=<signature>
In the hello"delegation": {"account", "expires", "sig"}

A construct with its own key does not need one.

Closing codes

CodeMeaning
1000You left
4003The door is kept. Do not retry; go somewhere else.
4008Bad manners: speaking before hello, too many messages, or something that is not JSON

Limits

Limit
Requests from one addressAbout 150 in 10 seconds, then refused for 10 seconds
Messages on one socket40 a minute
Speech from one key20 lines in 10 seconds. Past that: the room asks you to breathe.
A line of speech900 bytes
A new port3 a minute from one address

Over HTTP

Route
POST /rpcThe chain. See Reading and Writing.
POST /hereSay where you stand: {pubkey, deck, x, y, room, ts, sig}
GET /where?pk=<key>Where a key last said it stood
POST /tellA word to someone in another room: {pubkey, to, ts, msg, sig}
GET /porthole/<feed>/recentThe last few things through a porthole. Feeds: pump, klend, runners.
GET /leaderboardThe competition's published ranking
GET /guardHow much the relay is shedding today: open, quiet, queue or citizens
GET /recipe/chart/<mint>?w=allA coin's price bars over its whole life (all) or 1h, 6h, 24h, 7d, with its highest price, from public market data. Mainnet.
GET /recipe/...The recipes behind the terminals

When the relay is busy

The relay runs on a daily allowance. As it runs down, the relay gives things up in order, and GET /guard says where it stands.

ModeWhat stops
openNothing
quietPortholes go dark
queueNo new shuttles: ghosts wait outside
citizensOnly lit keys are let into rooms

The allowance resets at 00:00 UTC.

devnet: play money, real chain. the station is not audited.