Documentation for the app.nz AI agent cloud.
One control-plane API and one OpenAI-compatible model gateway, both authenticated with the same key. Launch coding agents on your repos, route chat across providers, and publish sites, all over HTTP. Every endpoint here maps to a live route in the Go server.
Authentication
Every API call authenticates with a bearer key created from your account. Pass it as an Authorization header. Browser sessions (cookie auth) work too, but keys are the right choice for servers, agents, and the CLI. Secrets are shown once at create/rotate time, so store them immediately.
/api/keysList keys (metadata only, no secrets)API key/api/keysCreate a key; response includes the one-time secretAPI key/api/keys/rotateRotate by id, by name, or all at onceAPI key/api/keys?id=key_123Revoke a keyAPI key/api/meCurrent account for the supplied key or sessionAPI key# Create a key (secret returned once)
curl -sX POST https://app.nz/api/keys \
-H "Authorization: Bearer $APP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"deploy bot"}'
# Use it on every other request
curl -s https://app.nz/api/me \
-H "Authorization: Bearer app_live_..."Models gateway
An OpenAI-compatible API in front of 15+ providers. Point any OpenAI or Anthropic client at the base URL and keep your code. Use app/auto to let the router pick a model from the prompt, or bias it with a variant, or pin a specific provider model. The same key meters usage across every call.
/v1/chat/completionsChat completions (streaming + tools)API key/v1/messagesAnthropic-compatible messages (supports thinking)API key/v1/modelsList routable models and aliasesAPI key/v1/embeddingsText embeddingsAPI key/v1/images/generationsImage generationAPI key/v1/audio/speechText-to-speechAPI key/v1/audio/transcriptionsAudio transcriptionAPI key/v1/searchWeb and papers searchAPI keyapp/autorouteDefault. Reads the prompt and picks the backend.app/auto-coderouteBias toward strong coding models.app/auto-fastrouteLowest latency for interactive use.app/auto-cheaprouteBias toward lowest cost per token.app/auto-reasoningrouteRoute reasoning depth automatically.app/auto-visionrouteBias toward image-input models.app/auto-imagerouteBias toward image-generation models.provider/modelpinPin a specific upstream model, e.g. anthropic/claude or openai/gpt.curl -s https://app.nz/v1/chat/completions \
-H "Authorization: Bearer app_live_..." \
-H "Content-Type: application/json" \
-d '{
"model": "app/auto",
"messages": [{"role": "user", "content": "Explain CRDTs in one paragraph."}],
"reasoning_effort": "auto",
"stream": false
}'Agents API
Run cloud coding agents against a repo and a prompt, then poll status, stream step events, inspect changed files, and cancel or retry. GET /api/agents/config returns the option lists (engines, models, reasoning efforts, machine types, providers, skills) and needs no auth so a UI can render the form before sign-in.
/api/agents/configOption lists for the agent formpublic/api/agents/tasksLaunch an agent taskAPI key/api/agents/tasksList your agent tasksAPI key/api/agents/tasks/{id}Get a task with its current statusAPI key/api/agents/tasks/{id}/eventsStep-by-step events and statusAPI key/api/agents/tasks/{id}/cancelCancel a running taskAPI key/api/agents/tasks/{id}/retryRetry a finished or failed taskAPI key/api/agents/tasks/{id}/filesList files the agent changedAPI key/api/agents/tasks/{id}/files/{fileId}Edit a changed file before reviewAPI keyprompt*stringWhat the agent should do (max 20k chars).repostringTarget repo as owner/name.branchstringWorking branch to create or use.baseBranchstringBranch to base the work on.modelstringModel route, e.g. app/auto-code.enginestringAgent engine (see /config).reasoningEffortstringnone | low | medium | high | auto.machineTypestringWorker size, e.g. cpx32.providerstringRepo/git provider (see /config).skillsstring[]Enabled skills, e.g. ["github","visualbench"].autoMergePrbooleanAuto-merge the PR when checks pass.autoNextStepsbooleanLet the agent queue follow-up steps.spendCapUsdnumberHard spend ceiling for the task.timeoutSecondsnumberWall-clock timeout.projectIdstringProject to bill and scope to; defaults to your default project.titlestringDisplay title; derived from the prompt if omitted.curl -sX POST https://app.nz/api/agents/tasks \
-H "Authorization: Bearer app_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "add usage analytics to the dashboard",
"repo": "acme/ai-dashboard",
"model": "app/auto-code",
"reasoningEffort": "high",
"machineType": "cpx32",
"skills": ["github", "visualbench"],
"spendCapUsd": 2.00,
"autoMergePr": false
}'Character chat API
Start chats with any character by url_name or id, pin a model for that chat, and stream replies over the same server-sent-events shape as the OpenAI-compatible gateway. User-created characters can include long-form text or Markdown documents; app.nz strips image links, chunks the text, stores it in the character vector-search boundary, and retrieves relevant excerpts for each turn.
/api/search-ais?q=luna&limit=20Find characters by name, title, tags, or descriptionpublic/api/get-ai-by-name?name=lunaLoad one character by url_name or display namepublic/api/charactersCreate a user-owned character and ingest text/Markdown docsAPI key/api/characters/{url_name}Update your character and optionally replace indexed docsAPI key/api/assistant/chatsCreate a chat for a character with a chosen modelAPI key/api/assistant/chats/{id}/messagesSend a turn and stream the character replyAPI key/api/assistant/chats/{id}Reload a chat and its active branchAPI keyname*stringPOST /api/characters display name.system_promptstringOptional persona prompt; generated from name/description/greeting if omitted.documentsarrayOptional long-form docs: [{ "name": "lore.md", "content": "# Markdown..." }]. Alias: knowledge_docs.character_url_name*stringPOST /api/assistant/chats target character slug.modelstringModel or route for this chat, e.g. app/auto or app/auto-fast.reasoning_effortstringauto | off | low | medium | high.content*stringMessage text for POST /messages.# Create a character with long-form Markdown knowledge.
curl -sX POST https://app.nz/api/characters \
-H "Authorization: Bearer app_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "GPU Brain Operator",
"description": "Helps operate the gpu-brain search stack.",
"voice": "Kore",
"documents": [{
"name": "runbook.md",
"content": "# Runbook\nUse gobed for low-latency KNN over text chunks. Never ingest image links."
}]
}'
# Start a chat with a given model.
CHAT=$(curl -sX POST https://app.nz/api/assistant/chats \
-H "Authorization: Bearer app_live_..." \
-H "Content-Type: application/json" \
-d '{
"character_url_name": "gpu-brain-operator",
"model": "app/auto-fast",
"reasoning_effort": "auto"
}' | jq -r .chat.id)
# Send a message. The response is text/event-stream; relevant doc excerpts are
# retrieved server-side before the model call.
curl -N -sX POST https://app.nz/api/assistant/chats/$CHAT/messages \
-H "Authorization: Bearer app_live_..." \
-H "Content-Type: application/json" \
-d '{"content":"What should I check if KNN search looks stale?"}'Sites API
Host a static site straight from the control plane. Create a slug, push files (index.html + assets, text or binary), and it is published instantly at both app.nz/sites/<slug>/ and its own subdomain <slug>.app.nz. No build step, no DNS wait. The subdomain is the right home for SPAs — bundlers emit absolute /assets/… paths that only resolve from a site root — and it is served straight from Cloudflare R2 at the edge, so static traffic never touches an origin. A fresh site is seeded with a working starter (index.html, styles.css, app.js). Slugs are 2–40 chars: lowercase letters, numbers, and hyphens, and a few reserved names are blocked. Files are up to 8 MB each; binary assets (images, fonts, audio) are stored too.
/api/sitesList your sitesAPI key/api/sitesCreate a site (seeds a starter)API key/api/sites/{id}Get a site with its filesAPI key/api/sites/{id}Delete a siteAPI key/api/sites/{id}/filesCreate or update a file (publishes)API key/api/sites/{id}/files?path=app.jsDelete a fileAPI key/sites/{slug}/{path}Public serving — no auth, defaults to index.htmlpublichttps://{slug}.app.nz/{path}Public serving on the site’s own subdomain (SPA-friendly)publicslug*stringPOST /api/sites — public name; normalized to a valid slug.titlestringPOST /api/sites — display title (max 120 chars).path*stringPUT files — file path, e.g. index.html or css/app.css.contentstringPUT files — UTF-8 file contents (max 8 MB). Use for text files.contentBase64stringPUT files — base64 bytes for binary files (images, fonts, audio).contentTypestringPUT files — overrides the type inferred from the extension.# Easiest: push a whole build directory with the app CLI. It creates the
# site on first run, uploads every text file, and prunes anything removed.
app login --api-key app_live_...
npm run build # e.g. Vite -> dist/
app sites deploy my-app dist --title "My app"
# Live at https://app.nz/sites/my-app/
# and https://my-app.app.nz/
# Or drive the REST API directly:
SITE=$(curl -sX POST https://app.nz/api/sites \
-H "Authorization: Bearer app_live_..." \
-H "Content-Type: application/json" \
-d '{"slug":"my-landing","title":"My landing"}')
ID=$(echo "$SITE" | jq -r .site.id)
# Publish index.html — live at /sites/my-landing/ and my-landing.app.nz
curl -sX PUT https://app.nz/api/sites/$ID/files \
-H "Authorization: Bearer app_live_..." \
-H "Content-Type: application/json" \
-d '{"path":"index.html","content":"<!doctype html><h1>Hi</h1>"}'Billing & plans
Everything is paid from one prepaid credit balance (credits are ~$0.001 each). On top of pay-as-you-go, a Pro ($20), Ultra ($60), or Max ($200) plan grants monthly credits, a guaranteed number of concurrent machines, and per-product free quotas. Plan credits are used before purchased credits and roll over for one month.
/api/pricingUsage-based pricing: model token rates, compute, search, credit unitpublic/api/plansList plan catalog (price, credits, machines, quotas)public/api/plans/meYour plan, credit balance, and product quota usageAPI key/api/plans/subscribeStart a Pro/Ultra/Max checkoutsession/api/plans/cancelCancel at period endsession/api/plans/portalOpen the Stripe billing portalsession/api/credits/balancePrepaid credit balance + auto-topupAPI key/api/credits/checkoutBuy credit packssession/api/credits/autotopupConfigure automatic top-upssessionfreeplan$0 — pay-as-you-go credits, shared worker pool.proplan$20/mo — 25,000 credits, 1 guaranteed machine.ultraplan$60/mo — 80,000 credits, 3 machines + priority.maxplan$200/mo — 280,000 credits, 6 machines + top priority.# Inspect the catalog
curl -s https://app.nz/api/plans | jq
# From the CLI (app login first)
app plan show
app plan subscribe ultra
app billing usageFirst-party products
RA1 art generation, paper search, and agentic search are first-party APIs metered against the same balance. Plan subscribers get a monthly free quota per product, consumed before any credits are charged. All three accept a Bearer key or a signed-in session.
/api/ra1/generateGenerate images with RA1 — prompt, count, aspect, style, negative (50 credits each)API key/api/ra1/statusPoll a queued render by jobId for status + image URLsAPI key/api/papers/searchSearch 200M+ papers (1 credit each)API key/api/searchAgentic web search (10 credits per depth)API keyapp chat "research R2-backed model hosting" --web --deep --papers
app ra1 generate --prompt "a cat astronaut" --count 2
app papers search "diffusion transformers" --limit 5
app search "best vector database 2026" --depth 2Conventions
- • Auth:
Authorization: Bearer app_live_...on every non-public route. - • Bodies and responses are JSON; successful writes return
{ "success": true, ... }. - • Errors return a non-2xx status with
{ "error": "message" }. - • Get a key with the CLI:
app keys create --name "deploy bot".