On this page
Core concepts
Authentication
JWTs for the dashboard, API keys for inference, and the account flows around them.
Every authenticated request uses Authorization: Bearer <token>. Auth resolution looks at the prefix: sk-or- is treated as an API key, anything else as a JWT.
Sign up
/auth/signupPubliccurl -X POST https://api.relayrouter.org/auth/signup \ -H 'content-type: application/json' \ -d '{ "email":"[email protected]", "password":"at-least-8-chars", "turnstile":"<captcha token>", "fingerprint":"<opaque device hash>" }'The signup gate
Signup is intentionally strict. Checks run in this order, so cheap rejections never consume a captcha token:
Signup errors
Fingerprint format
userAgent | languages | screen | timezoneOffset | hardwareConcurrency | deviceMemory | platform | maxTouchPoints | WebGL renderer. Send hex or URL-safe characters only, 16–128 chars. The server stores the hash, never raw device data.Sign in
/auth/signinPublicSame body and response as signup, without a captcha. The backend verifies the password with the credential authority, then mints an HS256 JWT locally containing sub, email, iat, and exp.
Sign-in resolves the canonical email, so an account created with [email protected] can sign in with [email protected] or [email protected]. Password reset behaves the same way.
Sign-in alerts
[email protected] with time, IP, and client. Alerts are deduped to one per IP per day and can be disabled with email_prefs.security = false.Current session
/auth/meJWT or API key{ "id": "998d9efd-1560-47d4-aa66-5919c1f236a3", "created_at": 1792276481, "email_verified": true, "role": "user", "is_admin": false, "balance_micro": 1522976, "balance_usd": 1.522976, "network_fee_micro": 100}balance_microis the source of truth.balance_usdis a convenience float.email_verifiedreflects the canonical verified flag. A completed deposit sets it.roleisuseroradmin, andis_adminis a convenience boolean. Admin accounts can call operator endpoints with their normal session.network_fee_micro:-1uses the model fee,0waives it, and a positive value is a custom fee for this account.
Not returned yet
/auth/me does not return token_limit, tokens_used, allowed_models, price_overrides, or token_multiplier. Use /usage for spend and the ops CLI for the rest.Email verification
Verification tokens are single-use and live 24 hours. Consuming one sets both verified and email_verified.
Password reset
/auth/forgot-passwordPublicAlways returns 200 so it never reveals whether an address is registered:
{ "ok": true, "message": "if that address is registered, a reset link is on its way"}Reset tokens are single-use and live 30 minutes. A successful reset burns every other outstanding reset token for the account.
Auth limits
Auth routes are limited to 2 req/s sustained, burst 30 per IP with a 45 second timeout. Surface a friendly "try again in a moment" on 429.