Thassa.

Start here

Getting started

Everything you need to make your first authenticated call: one account, one key, one header.

One account, app + API

Thassa has a single user base shared by the app and the API. There is no separate developer signup: your API keys act as you — same identity, same wallet, same positions, same balance. An order placed via the API shows up in your app profile, and vice versa.

  • Sign up in the app. Accounts (and the embedded wallet that signs your orders) are created in the Thassa app — the API has no signup endpoint.
  • Keys inherit your identity. Anything gated for your user in the app (visibility, limits) applies identically through a key.
  • Orders are still yours to sign. The API is non-custodial: mutating calls carry payloads signed by your own wallet. A key alone can never move funds — see Gasless orders.

Create an API key

In the web app, open Settings → Developer and create a key. Pick a name and a scope:

ScopeGrants
readAuthenticated reads: your orders, positions, fills, balance; WebSocket subscriptions.
tradeEverything in read, plus mutations: placing and canceling orders.

The secret is shown once

The full key secret is displayed only at creation. Secrets are stored hashed (SHA-256); afterwards only a prefix is shown for identification. Lose it and you mint a new key.

Keys can also be managed programmatically — see API keys endpoints.

Authentication

Pass the key on every authenticated request in the X-Thassa-Key header:

curl
curl "http://localhost:8080/trade-api/v1/balance" \
  -H "X-Thassa-Key: $THASSA_KEY"

The WebSocket accepts the same header on connect, or a ?key= query parameter where headers are unavailable — see WebSocket.

Environments & base URLs

All examples in these docs are rendered against the configured base URL — currently http://localhost:8080. The docs site reads it from NEXT_PUBLIC_API_URL at build time, so a deployment can point every snippet at its own environment.

EnvironmentBase URLNotes
Developmenthttp://localhost:8080Local backend from the repo’s single-command dev environment (Postgres, MinIO, Anvil chain fork).
This deploymenthttp://localhost:8080Baked into every example on this page.

Route prefixes, by audience:

  • /trade-api/v1/… — the public trading API documented here (market data + authenticated trading).
  • /v1/developer/keys — key management (app-session authenticated).
  • /v1/ws — the WebSocket endpoint, which accepts API-key auth for market-data channels.

Rate limits

  • Public market-data endpoints are rate-limited by IP.
  • Authenticated endpoints are rate-limited per key. Order placement additionally enforces per-user rate limits and a maximum order size at the relayer gate.

Exceeding a limit returns 429 with the standard error envelope. Back off and retry; idempotency keys (below) make retries safe.

Response envelope

Successful responses wrap data under a named key — never a bare array. List endpoints paginate with ?cursor=&limit= and return next_cursor (absent or null on the last page). Pass it back verbatim to fetch the next page.

GET /trade-api/v1/markets — 200
{
  "markets": [
    { "id": "42", "question": "…", "status": "OPEN", "yes_price_cents": 62 }
  ],
  "next_cursor": "eyJvZmZzZXQiOjUwfQ"
}

Error format

Every error — 4xx or 5xx — is a single lowercase message under error:

401 Unauthorized
{ "error": "invalid api key" }
StatusMeaning
400Malformed request — bad ids, unknown fields, invalid payloads.
401Missing or invalid X-Thassa-Key.
403Key lacks the required scope (e.g. read key on a mutation), or the resource is gated.
404No such resource.
409Idempotency-key conflict (same key, different request).
429Rate limit exceeded.
500Server error, message shaped "failed to …".

Idempotency-Key

Every mutating endpoint accepts an Idempotency-Key header — a client-generated UUID. Semantics:

  • First request executes normally; the response is stored against (key, user).
  • Replay (same key, byte-identical request) returns the stored response without re-executing — a double-submitted order never double-spends.
  • Conflicting reuse (same key, different request hash) is rejected with 409.
idempotent order placement
curl -X POST "http://localhost:8080/trade-api/v1/orders" \
  -H "X-Thassa-Key: $THASSA_KEY" \
  -H "Idempotency-Key: 7d1f6f0a-3f2e-4a4e-9df1-2c9b3f6a1e42" \
  -H "Content-Type: application/json" \
  -d @order.json

Note

Always send an Idempotency-Key on POST /trade-api/v1/orders. Networks fail mid-flight; with the key, retrying is always safe.

Where next