Developers

Key to live game in an afternoon.

Everything on this page is live today. Shapes are abbreviated for reading; the full REST and OpenAPI reference is at /docs.

Step one

Create an app, mint a key.

Register your app in the console and create a secret key. Keys are tenant-scoped: yours cannot see another app's players, and nobody else's can see yours.

# psk_ keys are secrets. Server-side only, never in a client build.
export PARLOR_KEY="psk_YOUR_KEY"
Step two

Provision a player, mint a token.

Players are provisioned by your user ids. Parlor never sees emails or names; it assigns each player a generated handle and a parts-based avatar. Player tokens expire, so mint one from your server when a session starts.

curl -X POST https://activities.daeila.com/v1/players/tokens \
  -H "Authorization: Bearer psk_YOUR_KEY" \
  -d '{"external_id":"user_42"}'

# response, abbreviated
{
  "token": "ppt_...",
  "expires_at": "2026-07-14T08:15:00Z"
}

Hand the ppt_ token to your client. It authorizes that one player, briefly, and nothing else.

Step three

Read the catalog.

The catalog lists what the network can play. Today that is chess: live 3+2 blitz, and a quick mode, a three-puzzle drill bounded under three minutes.

curl https://activities.daeila.com/v1/catalog \
  -H "Authorization: Bearer ppt_PLAYER_TOKEN"
Step four

Queue up, then speak socket.

The client joins the matchmaking queue with its player token. Matching is rating-banded and the band widens while you wait; if a fair human match has not filled in about 15 seconds, you know in time to offer a bot fallback. When a match fills, the client opens the match WebSocket.

DirectionMessageWhat happens
Client sends {"type":"move","uci":"g1f3"} Validated server-side against the authoritative position. Illegal moves are rejected and the position does not change.
Client sends {"type":"resign"} Ends the game immediately. The result and rating change commit in one transaction.
Server pushes state frame The authoritative position, server clocks, and status. Pushed after every accepted move and on clock events. Your client renders it and nothing more.
Server pushes final state frame Marks the game over, whether by mate, resignation, timeout, or abandonment after disconnect grace runs out, and carries the result.
# a state frame, the only thing your renderer needs
{
  "type": "state",
  "fen": "r1bqk2r/ppp2ppp/2np1n2/2b1p1N1/2B1P3/2PP4/PP3PPP/RNBQK2R b KQkq - 5 6",
  "turn": "black",
  "clocks": { "white_ms": 158200, "black_ms": 153000 },
  "last_move": "f3g5",
  "status": "active"
}
Step five

Record sessions, verify receipts.

Start a quick-mode session with a ref you choose, then verify it from your server. The receipt carries completed_received_at stamped by the server clock. That is how you know a gate was really completed. Trust receipts, not clients.

curl "https://activities.daeila.com/v1/sessions?ref=wake_2026-07-14_user_42" \
  -H "Authorization: Bearer psk_YOUR_KEY"

# response, abbreviated
{
  "sessions": [
    {
      "ref": "wake_2026-07-14_user_42",
      "activity": "chess",
      "mode": "quick",
      "completed_received_at": "2026-07-14T07:03:11Z"
    }
  ]
}

This is the pattern behind AlarmMCP's wake checks: the alarm is satisfied by the receipt, not by the phone's word.

SDKs

REST-first, on purpose.

The API surface is small enough that most stacks need no SDK: three REST calls and a WebSocket. ParlorKit, a Swift package, exists in early access for native Apple clients. SDKs for more platforms are on the roadmap, which means they are not shipped.