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#
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/meOn 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.
| Provider | Header | rush http flag |
|---|---|---|
X-Google-Access-Token | --oauth google | |
X-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.
| Method | Path | Notes |
|---|---|---|
| GET | /api/v1/packages/:packageId/manifest | Manifest for a developer/agent pair. |
| GET | /api/v1/packages/:packageId/latest | Latest version pointer. |
| GET | /api/v1/packages/:packageId/:version | Version-pinned manifest (semver). |
| GET | /api/v1/packages/:packageId/keys/:version | DEK for an installed container. |
| POST | /api/v1/download/:packageId | Issues a presigned download URL. |
| POST | /api/v1/publish | Publish 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/modelsDefined 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.
| Provider | URL | Callback | Refresh | Revoke |
|---|---|---|---|---|
GET /api/v1/auth/google/url | GET /api/v1/auth/google/callback | POST /api/v1/auth/google/refresh | POST /api/v1/auth/google/revoke | |
| Microsoft | GET /api/v1/auth/microsoft/url | GET /api/v1/auth/microsoft/callback | POST /api/v1/auth/microsoft/refresh | POST /api/v1/auth/microsoft/revoke |
GET /api/v1/auth/twitter/url | GET /api/v1/auth/twitter/callback | POST /api/v1/auth/twitter/refresh | POST /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")).
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/gmail/messages | List inbox messages. |
| GET | /api/v1/gmail/messages/:id | Fetch a single message. |
| PATCH | /api/v1/gmail/messages/:id/labels | Add/remove labels. |
| GET | /api/v1/gmail/search | Search messages. |
| POST | /api/v1/gmail/drafts | Create a draft. |
| POST | /api/v1/gmail/drafts/:id/send | Send a previously-created draft. |
| POST | /api/v1/gmail/drafts/batch-delete | Delete multiple drafts in one call. |
| POST | /api/v1/gmail/send | Send a new email directly. |
| POST | /api/v1/gmail/send-attachment | Send an email with an attachment. |
| GET | /api/v1/gmail/labels | List labels. |
| GET | /api/v1/gmail/threads/:id | Fetch 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
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/gcal/events | List calendar events. |
| POST | /api/v1/gcal/events | Create a calendar event. |
| GET | /api/v1/gcal/calendars | List calendars. |
| POST | /api/v1/google/sheets/create | Create a Google Sheet. |
| POST | /api/v1/docs/create | Create a Google Doc. |
| GET | /api/v1/contacts/lookup | Look up a Google contact by email. |
Defined in prix/api/src/index.ts:3129–3186.
All Twitter routes require the bearer plus X-Twitter-Access-Token (see prix/api/src/twitter/index.ts:171).
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/twitter/tweets | Post a tweet. |
| GET | /api/v1/twitter/me | Authenticated profile with cached avatar. |
| GET | /api/v1/twitter/tweets/me | Your recent tweets. |
| GET | /api/v1/twitter/timeline | Home timeline. |
| GET | /api/v1/twitter/mentions | Mentions of the authenticated user. |
| GET | /api/v1/twitter/followers | Followers list. |
| GET | /api/v1/twitter/tweets/:id | Fetch a specific tweet. |
| DELETE | /api/v1/twitter/tweets/:id | Delete a tweet. |
| GET | /api/v1/twitter/search | Search 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).
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/microsoft/messages | List Outlook messages. |
| GET | /api/v1/microsoft/messages/:id | Fetch a single Outlook message. |
| POST | /api/v1/microsoft/send | Send an Outlook message. |
| GET | /api/v1/microsoft/calendar/events | List calendar events. |
| POST | /api/v1/microsoft/calendar/events | Create a calendar event. |
| GET | /api/v1/microsoft/contacts | List contacts. |
| GET | /api/v1/microsoft/files | List 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 }| Field | Type | Notes |
|---|---|---|
email | string | Required. Lower-cased and validated against an email regex. Max 254 chars. |
source | string | Optional. 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.
| Code | User-facing message | Trigger |
|---|---|---|
timeout | Request timed out — try again | timeout / deadline exceeded |
rate_limited | Busy right now — try again in a moment | 429 / rate limit / too many requests |
auth_failed | Connection error — restart the app | 401 / 403 / unauthorized / forbidden |
server_unavailable | Service temporarily unavailable — try again shortly | 502 / 503 / unavailable |
model_not_found | This agent is temporarily unavailable | unsupported / unknown / model not found |
bad_request | Invalid request to model provider | 400 |
execution_error | Model call failed | fallback 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).
| Bucket | Endpoint | Limit |
|---|---|---|
waitlist | POST /api/v1/waitlist | TODO: confirm with founder |
llm | POST /api/v1/proxy | TODO: confirm with founder |
execute | POST /api/v1/agents/:id/execute | Per-agent execution quota (per-subscription). |