Docs

API Reference

HTTP reference for api.prix.dev — the LLM proxy, agent registry, agent execution, and OAuth passthrough endpoints that power Rush.

At a glance#

Auth
Catalog
Session
Execute
Google
Twitter

The Prix API runs at https://api.prix.dev. Every authenticated route expects a Supabase session token in the Authorization header. OAuth-proxy routes (Gmail, Google Calendar, Twitter, etc.) additionally take a provider access token in a service-specific header — the bearer auths the Rush user, the provider token authorises the third-party call.

Use rush http instead of raw curl. It loads the session token from ~/.rush/user.yaml, refreshes on 401, and lets you tag a provider with --oauth google or --oauth twitter.

Authentication#

Two layers of credentials. The session token authenticates you as a Rush user — every authenticated endpoint requires it. Provider tokens (Google, Twitter, Microsoft, etc.) authorise the API to call third-party services on your behalf — only OAuth-passthrough endpoints need them.

Bearer session token

The bearer token is a Supabase access token. Send it in the Authorization header. Tokens expire — refresh them through the Rush app or let rush http handle it for you.

# Authorization header (required for authenticated routes)
Authorization: Bearer <supabase-access-token>

# Same call via rush http (token auto-injected from ~/.rush/user.yaml)
rush http GET /api/v1/auth/me

On the server, the token is validated in getAuthenticatedUser():

// prix/api/src/auth.ts:80
if (authHeader?.startsWith("Bearer ")) {
  token = authHeader.slice(7);
}
// ...
if (!token) {
  throw new AppError("AUTH_FAILED", "Missing authorization - use Authorization header");
}

Provider access tokens

OAuth-proxy endpoints accept a per-provider header alongside the bearer. The header carries the access token the API uses to call Google, Twitter, etc.

ProviderHeaderrush http flag
GoogleX-Google-Access-Token--oauth google
TwitterX-Twitter-Access-Token--oauth twitter
# Gmail call via rush http (injects both headers)
rush http GET /api/v1/gmail/messages --oauth google

# Tweet via rush http
rush http POST /api/v1/twitter/tweets --oauth twitter -d '{"text":"Hello"}'

The two-token pattern is documented in rush/cli/docs/authenticated-api-calls.md. URLs that start with / are auto-prefixed to https://api.prix.dev.

Catalog#

The catalog is the public list of agents published to the Rush registry. GET /api/v1/catalog returns a presigned R2 URL rather than the catalog body directly — fetch the catalog in two steps.

GET /api/v1/catalog

Returns a JSON object with a single url field — a short-lived presigned URL for catalog.json on R2. Fetch that URL with plain curl (no auth) to get the full catalog body.

# Step 1: get the presigned URL
rush http GET /api/v1/catalog
# => { "url": "https://halo-registry...r2.cloudflarestorage.com/catalog.json?X-Amz-..." }

# Step 2: fetch the actual catalog
curl -s "<presigned-url-from-step-1>"

Route definition: prix/api/src/index.ts:1105 — if (path === "/api/v1/catalog" && req.method === "GET"). Concrete shape of the response body lives in prix/api/docs/fetching-the-catalog.md.

Package endpoints

The CLI uses these directly during rush install. They're also part of the public registry surface.

MethodPathNotes
GET/api/v1/packages/:packageId/manifestManifest for a developer/agent pair.
GET/api/v1/packages/:packageId/latestLatest version pointer.
GET/api/v1/packages/:packageId/:versionVersion-pinned manifest (semver).
GET/api/v1/packages/:packageId/keys/:versionDEK for an installed container.
POST/api/v1/download/:packageIdIssues a presigned download URL.
POST/api/v1/publishPublish a built agent. Developer Mode required.

Defined in prix/api/src/index.ts:1132–1186 (manifest, latest, keys, version, download, publish).

GET /api/v1/models

Returns the list of LLM models the proxy will accept. No auth — the list is public so agent developers can pick models without signing in.

curl -s https://api.prix.dev/api/v1/models

Defined in prix/api/src/index.ts:1090.

User & session#

Inspect the authenticated user, sign in/out via OAuth, and probe service health.

GET /api/v1/auth/me

Returns the user behind the bearer token. Useful for rush whoami-style probes and for validating that a session is still live.

rush http GET /api/v1/auth/me
# 200
# {
#   "userId": "...",
#   "email": "[email protected]",
#   "valid": true
# }
# 401
# { "valid": false, "error": "Invalid or expired token" }

Defined in prix/api/src/index.ts:2070.

GET /health and /api/v1/status

/health is the cheap liveness probe — returns the string ok. /api/v1/status probes DB, R2, and the LLM provider in parallel and returns a structured component map.

# Liveness — used by load balancers
curl -s https://api.prix.dev/health
# ok

# Component status — used by uptime monitors
curl -s https://api.prix.dev/api/v1/status
# {
#   "ok": true,
#   "components": { "db": "up", "r2": "up", "llm": "up" },
#   "groups":     { "api": "up", "catalog": "up", "proxy": "up", "auth": "up", "store": "up", "sharing": "up" },
#   "latency_ms": { ... },
#   "ts": "..."
# }

Defined in prix/api/src/index.ts:686 and prix/api/src/index.ts:697.

OAuth proxy passthrough#

These routes take a Rush session bearer and a provider access token, then call the underlying provider on your behalf. They exist so agents can talk to Google or Twitter without each agent re-implementing OAuth.

OAuth flow endpoints

Used by the Rush app to start, complete, refresh, and revoke provider connections. Most users never call these directly — they run when you click “Connect Google” in the app.

ProviderURLCallbackRefreshRevoke
GoogleGET /api/v1/auth/google/urlGET /api/v1/auth/google/callbackPOST /api/v1/auth/google/refreshPOST /api/v1/auth/google/revoke
MicrosoftGET /api/v1/auth/microsoft/urlGET /api/v1/auth/microsoft/callbackPOST /api/v1/auth/microsoft/refreshPOST /api/v1/auth/microsoft/revoke
TwitterGET /api/v1/auth/twitter/urlGET /api/v1/auth/twitter/callbackPOST /api/v1/auth/twitter/refreshPOST /api/v1/auth/twitter/revoke

Defined in prix/api/src/index.ts:2089–2171. Notion, Slack, and Pinterest follow the same shape — see lines 2139–2228.

Gmail

All Gmail routes require the bearer plus X-Google-Access-Token. Each handler reads the provider token directly — see prix/api/src/gmail/index.ts:505 (const googleToken = req.headers.get("X-Google-Access-Token")).

MethodPathPurpose
GET/api/v1/gmail/messagesList inbox messages.
GET/api/v1/gmail/messages/:idFetch a single message.
PATCH/api/v1/gmail/messages/:id/labelsAdd/remove labels.
GET/api/v1/gmail/searchSearch messages.
POST/api/v1/gmail/draftsCreate a draft.
POST/api/v1/gmail/drafts/:id/sendSend a previously-created draft.
POST/api/v1/gmail/drafts/batch-deleteDelete multiple drafts in one call.
POST/api/v1/gmail/sendSend a new email directly.
POST/api/v1/gmail/send-attachmentSend an email with an attachment.
GET/api/v1/gmail/labelsList labels.
GET/api/v1/gmail/threads/:idFetch a thread.

Defined in prix/api/src/index.ts:2988–3058.

rush http GET /api/v1/gmail/messages --oauth google
rush http POST /api/v1/gmail/send --oauth google -d '@./body.json'

Google Calendar & Sheets

MethodPathPurpose
GET/api/v1/gcal/eventsList calendar events.
POST/api/v1/gcal/eventsCreate a calendar event.
GET/api/v1/gcal/calendarsList calendars.
POST/api/v1/google/sheets/createCreate a Google Sheet.
POST/api/v1/docs/createCreate a Google Doc.
GET/api/v1/contacts/lookupLook up a Google contact by email.

Defined in prix/api/src/index.ts:3129–3186.

Twitter

All Twitter routes require the bearer plus X-Twitter-Access-Token (see prix/api/src/twitter/index.ts:171).

MethodPathPurpose
POST/api/v1/twitter/tweetsPost a tweet.
GET/api/v1/twitter/meAuthenticated profile with cached avatar.
GET/api/v1/twitter/tweets/meYour recent tweets.
GET/api/v1/twitter/timelineHome timeline.
GET/api/v1/twitter/mentionsMentions of the authenticated user.
GET/api/v1/twitter/followersFollowers list.
GET/api/v1/twitter/tweets/:idFetch a specific tweet.
DELETE/api/v1/twitter/tweets/:idDelete a tweet.
GET/api/v1/twitter/searchSearch recent tweets.

Defined in prix/api/src/index.ts:3451–3519.

rush http POST /api/v1/twitter/tweets --oauth twitter \
  -d '{"text":"Hello from Rush"}'

Microsoft Graph

Mail, calendar, contacts, and OneDrive via Microsoft Graph. Bearer plus a Microsoft access token (see prix/api/src/index.ts:3066–3111).

MethodPathPurpose
GET/api/v1/microsoft/messagesList Outlook messages.
GET/api/v1/microsoft/messages/:idFetch a single Outlook message.
POST/api/v1/microsoft/sendSend an Outlook message.
GET/api/v1/microsoft/calendar/eventsList calendar events.
POST/api/v1/microsoft/calendar/eventsCreate a calendar event.
GET/api/v1/microsoft/contactsList contacts.
GET/api/v1/microsoft/filesList OneDrive files.

Waitlist#

Public, unauthenticated. IP rate-limited via checkRateLimit(clientId, "waitlist").

POST /api/v1/waitlist

Adds an email to the waitlist. No bearer required.

curl -s -X POST https://api.prix.dev/api/v1/waitlist \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","source":"getrush.ai"}'
# { "ok": true }
FieldTypeNotes
emailstringRequired. Lower-cased and validated against an email regex. Max 254 chars.
sourcestringOptional. Allowed: "getrush.ai", "prix.dev". Unknown values fall back to "getrush.ai".

Defined in prix/api/src/index.ts:762–786.

Agent invocation#

Invoke a published agent server-side. The handler spawns the rush CLI in --serve-mode and streams events over Server-Sent Events. For long-lived public endpoints, prefer rush deploy — see Serve & Deploy.

POST /api/v1/agents/:id/execute

:id must match the pattern developer/slug (alphanumeric + hyphens/underscores, single slash). Body: prompt required, session_id optional. Response is an SSE stream of execution events.

rush http POST /api/v1/agents/prix/rabbit-hole/execute \
  -d '{"prompt":"Research quantum computing","session_id":"session_abc"}'

Defined in prix/api/src/routes/agent-execute.ts:7 (Hono route) and prix/api/src/routes/execute.ts:22 (handler). Path pattern /^\/api\/v1\/agents\/[^/]+\/execute$/ is also matched in prix/api/src/index.ts:729 for the Hono dispatch.

The handler checks an agent subscription before spawning. When the user's execution quota is exhausted it returns 402 Payment Required with code: "QUOTA_EXCEEDED" and an upgrade-checkout URL (see prix/api/src/routes/execute.ts:53–82).

POST /api/v1/proxy

The LLM proxy. Agents call this to invoke a model — the request shape mirrors the upstream provider, the proxy authenticates the Rush user, enforces quotas, and forwards the call.

# Bearer required. Body passes through to the upstream provider.
rush http POST /api/v1/proxy -d '@./model-request.json'

Defined in prix/api/src/index.ts:727 (dispatch) and prix/api/src/routes/proxy.ts:9 (Hono handler chained through requireAuthWithOrg + requireLimits).

Errors#

Errors flow through the stack as structured codes, not raw strings. The CLI's classifyError() maps any error into { message, code } and writes both error_code and a user-friendly error field to messages. The Rush app renders error_code — users never see raw provider strings.

CodeUser-facing messageTrigger
timeoutRequest timed out — try againtimeout / deadline exceeded
rate_limitedBusy right now — try again in a moment429 / rate limit / too many requests
auth_failedConnection error — restart the app401 / 403 / unauthorized / forbidden
server_unavailableService temporarily unavailable — try again shortly502 / 503 / unavailable
model_not_foundThis agent is temporarily unavailableunsupported / unknown / model not found
bad_requestInvalid request to model provider400
execution_errorModel call failedfallback for everything else
quota_exceeded(structured upgrade prompt)QuotaExceededError from agent execute

Source of truth: harness/agent/agent.go:579–625 defines errorClassification and classifyError(); buildErrorMessage() at harness/agent/agent.go:628 writes error_code, error, and details onto the message; the app maps codes to user-friendly text in rush/app/src/lib/formatting.ts.

Server-side, auth failures throw new AppError("AUTH_FAILED", ...) (see prix/api/src/auth.ts:94). Quota-exhausted /agents/:id/execute responses come back as HTTP 402 with code: "QUOTA_EXCEEDED" and a populated subscription block — clients render an upgrade button rather than a raw error.

Rate limits

Public endpoints are IP-rate-limited via checkRateLimit(clientId, bucket). The waitlist route at prix/api/src/index.ts:766 uses the "waitlist" bucket. Authenticated routes go through requireLimits("llm") middleware (see prix/api/src/routes/proxy.ts:8) — exhausted quotas return 429 (rate) or 402 (subscription).

BucketEndpointLimit
waitlistPOST /api/v1/waitlistTODO: confirm with founder
llmPOST /api/v1/proxyTODO: confirm with founder
executePOST /api/v1/agents/:id/executePer-agent execution quota (per-subscription).

Next#

Documentation | Prix | Prix