Wattfare / Docs
Dashboard
Platform

HTTP API

The raw REST API the SDK wraps. You rarely call this directly — the SDK handles auth, token caching, and error typing — but it's here for debugging, non-JS stacks, and custom integrations.

Authentication

Two bearer schemes, for two trust levels:

SchemeHeaderUsed by
Secret keyAuthorization: Bearer sk_live_{appId}_{secret}Server-to-server: sessions, status, chat completions
Session tokenAuthorization: Bearer {jwt}Browser: the /connections endpoints (via the SDK)

Session tokens are JWTs with a 10-minute TTL carrying the app id, your user id, and the requested limits. Mint them with POST /sessions; the SDK caches and refreshes them for you.

POST /sessions

Mints a frontend session token. Requires secret-key auth.

request
POST /api/v1/sessions
Authorization: Bearer sk_live_{appId}_{secret}
Content-Type: application/json

{
  "appUserId": "user_123",
  "requestLimit": { "monthlyUsd": 20 }   // optional
}
response
200 OK
{
  "token": "eyJhbGciOi…",   // short-lived JWT for the frontend
  "expiresAt": 1718400000   // unix seconds (default TTL: 10 min)
}

Rate limited per app via RL_SESSIONS — 120 requests/minute.

/connections

The consent surface, authed with a session token (not the secret key). The SDK's connect(), status(), and disconnect() map onto these.

connections
# Approve / update — body { monthlyUsd? }, returns ConnectionStatus
POST   /api/v1/connections     Authorization: Bearer {session-jwt}

# Read current status
GET    /api/v1/connections     Authorization: Bearer {session-jwt}

# Revoke
DELETE /api/v1/connections     Authorization: Bearer {session-jwt}
MethodBodyReturns
POST{ monthlyUsd? }ConnectionStatus — approve or update the cap
GETConnectionStatus
DELETE204 — revoke the connection

GET /status

Server-side connection check, keyed by your user id. Requires secret-key auth.

request
GET /api/v1/status?appUserId=user_123
Authorization: Bearer sk_live_{appId}_{secret}
response
200 OK
{
  "connected": true,
  "limits":   { "monthlyUsd": 10 },
  "usage":    { "monthlyUsd": 3.20 },
  "remainingUsd": 6.80
}

POST /chat/completions

The OpenAI-compatible inference proxy. Requires secret-key auth and the x-wattfare-user header so Wattfare resolves the right connection and budget.

request
POST /api/v1/chat/completions
Authorization: Bearer sk_live_{appId}_{secret}
x-wattfare-user: user_123
Content-Type: application/json

{
  "model": "openai/gpt-4o-mini",
  "messages": [{ "role": "user", "content": "Hello" }],
  "stream": true
}

Responds with the standard OpenAI chat-completion format — JSON, or an SSE stream when "stream": true. Usage is metered automatically: cost is read from the provider's usage object and stored per-user, per-period. The stream is teed, never buffered.

curl
curl https://wattfare.com/api/v1/chat/completions \
  -H "Authorization: Bearer $WATTFARE_SECRET_KEY" \
  -H "x-wattfare-user: user_123" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "messages": [{ "role": "user", "content": "Say hi" }]
  }'

One-time grants

For apps without a user system, grants provide a simpler flow: the browser requests a grantToken via the consent popup, and the backend redeems it with the x-wattfare-grant header. See One-time grants for endpoints and examples.

Errors

Every error responds with the same body shape and a meaningful status:

error body
{ "error": { "code": "budget_exceeded", "message": "Spending cap reached for this period." } }
StatuscodeMeaning
400invalid_requestMalformed body or parameters.
401authMissing/invalid secret key or session token.
402not_connectedUser hasn't connected a budget.
402budget_exceededMonthly cap reached.
402grant_invalidThe grant token is unknown, expired, fully used, or over its dollar cap.
402funding_invalidUser's funding source rejected upstream (reconnect needed).
429rate_limitedPer-user inference limit — 30 requests/min per app-user.
502upstreamThe model provider returned an error.

Rate limits

LimiterScopeLimit
RL_SESSIONSper app120 / minute
RL_CHATper app + user30 / minute