Auth.

RelayStation accepts three credentials, plus one transitional path retiring post-Phase C. Pick whichever fits your agent or your human session; the leases they produce are identical.

The API identifies callers as either an account actor (authenticated via API key or account JWT) or a wallet actor (x402 payment, or the transitional wallet-signature JWT). A lease is owned by whichever kind of actor created it; see Leases → Ownership.

The three paths

1. rs_live_ API key

A prepaid-balance credential under an account. Opaque token, Authorization: Bearer rs_live_…. Best for long-running agents, CI pipelines, and server-side automation.

2. Account JWT (OAuth-issued)

A session token minted at OAuth sign-in. 30-day TTL, type: 'account', issuer: 'relaystation'. Best for human sessions on the dashboard. Agents should prefer API keys — JWTs rotate and expire on a schedule you don't control.

3. x402 wallet signature

Pay USDC on Base per request. The agent attaches an X-Payment header produced by an x402 client; the on-chain payment is both identity and authorization. No account, no prior relationship to RelayStation. Best for ephemeral agents that don't outlive a single task.

Transitional: wallet-signature JWT

Retiring post-Phase C. The legacy wallet-signature JWT (payload { wallet }, no type, no issuer) is recognized for dashboard-adjacent endpoints during the migration window so that pre-OAuth wallet users don't lose access. New integrations should use an rs_live_ API key or account JWT instead.

Grep marker in the codebase: [PHASE-C wallet-JWT transitional branch]. When that branch is removed, wallet-signature JWTs stop working.

Which middleware runs on which endpoint

Three gates, layered.

requireAuth
Strict. Accepts rs_live_ API keys and account JWTs. Populates req.account. Guards every /v1/account/* endpoint and (for the most part) the lease-creation endpoints.
requireDashboardAuth
Lenient transitional. Everything requireAuth accepts, plus legacy wallet-signature JWTs. Populates req.account or req.wallet depending on the path taken. Guards dashboard-adjacent endpoints that need to cover both pre-OAuth and post-OAuth users during Phase C.
requireAccountOrWalletAuth
The lease-creation gate. Accepts an API key / account JWT (billed to prepaid balance) OR an x402 X-Payment header (billed on-chain). Never falls through to wallet-signature JWT — unpaid wallet sessions cannot create leases.

Picking a path

Which credential each endpoint accepts

Authoritative matrix. Columns are the four credential kinds; cells mark acceptance per endpoint. marks paths that accept the transitional wallet-signature JWT (retires post-Phase D); new integrations shouldn't rely on these. marks endpoints that don't use the Authorization header at all (the URL or drop-token IS the credential, or the endpoint is a pre-auth entrypoint).

Endpoint wallet-JWT account-JWT rs_live_ x402
Storage
POST /api/store
GET /api/download/:lease_id
GET /api/leases
Mailbox
POST /api/mailbox
GET /api/mailboxes
POST /api/mailbox/:drop_token/drop — drop token is the credential (no auth header)
GET /api/mailbox/:id/messages
GET · DELETE /api/mailbox/:id/messages/:mid
DELETE /api/mailbox/:id
Checkpoint
POST /api/checkpoint
GET /api/checkpoints
GET · PUT · DELETE /api/checkpoint/:workflow_id
Handoff (cross-variant)
POST /api/handoff/:lease_id
GET /api/handoffs/:lease_id
DELETE /api/handoffs/:id
GET /api/claim/:token — claim token is the credential (no auth header)
Account & billing
GET /v1/account/me
GET /v1/account/ledger
GET · POST · DELETE /v1/account/api-keys
POST /v1/billing/checkout
Auth entrypoints
GET /v1/auth/google/start · /v1/auth/github/start — pre-auth (no credential yet; OAuth redirect flow issues the account JWT)

Two things to note about the column. First: every also carries a in a non-transitional column — the wallet-JWT path is a bonus acceptance, not a required one. Second: lease creation (POST /api/store, /api/mailbox, /api/checkpoint) is the single group that never accepts wallet-JWT. Wallet actors pay for leases via x402 at the moment of creation; they don't have a prepaid balance to debit.

Where credentials go

Every authenticated endpoint reads a single Authorization header:

headers
# API key
Authorization: Bearer rs_live_a1b2c3d4e5f6…

# account JWT (OAuth-issued)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs…

# wallet-signature JWT (transitional)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs…

x402 payments ride in X-Payment instead — never in Authorization. A request carrying both is treated as x402-first at the lease-creation gate; other gates reject x402 outright because they don't price per call.

Next
Errors