{"name":"PaperPod","schemaVersion":"2026-01-26","apiVersion":"v2","description":"Agent-native, pay-per-execution compute infrastructure","baseUrl":"https://paperpod.dev","previewUrlDomain":"paperpod.work","quickStart":{"step1":"Get token: curl -X POST https://paperpod.dev/login -d '{\"email\":\"you@email.com\"}' → check email → click magic link → copy token","step2":"Install & login: npm install -g @paperpod/cli && ppod login <your-token>","step3":"Try it: ppod exec 'echo hello world' && ppod status"},"agentStartPrompt":"To use PaperPod: 1) Get token: POST /login with {\"email\":\"you@email.com\"}, click magic link, copy token. 2) Install & login: npm install -g @paperpod/cli && ppod login <token>. 3) Try it: ppod exec 'echo hello' && ppod status. Features: code execution, processes, preview URLs, Agent Memory, Browser (Playwright), AI models. Pricing: $0.0001/sec compute+browser, $0.02/1K neurons AI. $5 free credits.","skills":{"websocket":true,"streaming":true,"python":true,"javascript":true,"git":true,"backgroundProcesses":true,"fileSystem":true,"portExposure":true,"richOutput":true,"sessionPersistence":true,"agentMemory":true,"browserRendering":true,"workersAI":true},"environment":{"isolation":"Each user gets their own container with a full Linux environment - you can only affect your own ephemeral sandbox","python":"python or python3 (both work)","pip":"pip, pip3, or python3 -m pip (all work)","javascript":"node (default) / bun (faster, TS-native)","git":"git clone, git pull, git commit","shell":"bash","tools":{"runtimes":["python","python3","pip","pip3","node","npm","npx","bun","bunx"],"versionControl":["git","gh"],"httpNetworking":["curl","httpie","jq","dig","ss"],"searchText":["ripgrep","find","sed","awk","tree"],"mediaDocs":["ffmpeg","imagemagick","pandoc"],"buildData":["make","sqlite3","tar","gzip","zip","unzip"]},"reservedPorts":"3000-3010 (system use)"},"tips":{"runtimes":{"node":"Default JavaScript runtime. Maximum compatibility with npm packages.","bun":"Faster cold starts, native TypeScript. Use for speed-critical tasks.","hint":"For maximum compatibility, prefer node. For speed and TypeScript, use bun."},"shellTools":{"important":"All three languages work: python, javascript, and shell. Use --lang shell for direct shell commands.","cli":"ppod exec 'git --version' --lang shell","http":"POST /execute with { code: 'git --version', language: 'shell' }","gotchas":{"pip issues":"Both 'pip' and 'python3 -m pip' work. Use 'pip3' if pip conflicts with system.","empty stdout":"Many tools (ffmpeg, dig, gh) output to stderr. Check result.stderr too.","command timeout":"Add timeout param to subprocess or increase API timeout","file paths":"Use /tmp/ or /workspace/ for file operations. For POST /watch and ppod watch, use absolute paths like /workspace for now."},"networkAccess":"Outbound network works: DNS lookups, git clone, HTTP requests all allowed","examples":{"ripgrep":"rg --line-number 'def ' /tmp/project","jq":"cat data.json | jq '.users[].name'","ffmpeg":"ffmpeg -f lavfi -i sine=frequency=440:duration=3 tone.wav","imagemagick":"convert -size 200x100 gradient:blue-red gradient.png","pandoc":"pandoc doc.md -o doc.html","sqlite3":"sqlite3 app.db 'SELECT * FROM users'","git":"git clone --depth 1 https://github.com/user/repo /tmp/repo"}},"cli":{"recommended":"Use CLI for interactive use and multi-step workflows.","install":"npm install -g @paperpod/cli","tokenMethods":{"cliLogin":"ppod login pp_sess_... (saves to ~/.paperpod/config.json)","envVar":"export PAPERPOD_TOKEN=pp_sess_... (for scripts/CI)","perRequest":"-H 'Authorization: Bearer pp_sess_...' (for HTTP one-shots)"},"discover":"ppod help shows all available commands"},"websocket":{"note":"CLI uses WebSocket internally. Use WebSocket directly only for custom integrations.","messageFormat":"Responses use msg.data.X for payload fields (not msg.X)","discoverCommands":"Send { type: 'help' } after connecting to get full API schema"},"persistence":{"sandboxFiles":"Ephemeral - lost when session ends. Use /workspace or /tmp paths.","agentMemory":"Persistent - survives session resets. 10MB quota. Use /memory/* endpoints.","watchPaths":"For POST /watch and ppod watch, prefer absolute paths like /workspace. A relative value like workspace currently resolves to /workspace/workspace and fails."},"expose":{"tip":"Start your server FIRST, wait 1-2 seconds, THEN call /expose","urlFormat":"https://{port}-{id}-p{port}_v1.paperpod.work (stable URL)"},"proactiveSuggestions":{"description":"PaperPod automatically detects helpful situations and sends suggestion messages","example":"When a server starts listening on a port, you receive: { type: 'suggestion', data: { message: '...', category: 'port_detected', action: { type: 'expose', port: 8080 } } }"},"responseHints":{"description":"Process start responses include hints for next steps","fields":["hints.exposePort","hints.checkStatus","hints.stopProcess","hints.bindAddress"]},"errorActions":{"description":"Error responses include actionable info for agents","example":"{ error: '...', code: 'OUT_OF_CREDITS', action: 'TOP_UP', topupUrl: '...', agentInstruction: 'Call POST /topup with {tier} or {amountCents}, send X-Session-Token, and let an MPP client answer the payment challenge.' }"}},"recommended":{"api":"cli","reason":"CLI handles streaming, sessions, and reconnection automatically. Easiest way to use PaperPod.","cli":{"install":"npm install -g @paperpod/cli","login":"ppod login pp_sess_...","discover":"ppod help","commandHelp":"ppod <cmd> --help","execute":"ppod exec 'python script.py'"},"httpNote":"HTTP endpoints for one-shot tasks or when CLI isn't available.","websocketNote":"WebSocket for programmatic integrations (the CLI uses it internally)."},"billing":"Pay per request. Top up via MPP with Tempo or Stripe.","authentication":{"flow":"Email magic link → PaperPod token (pp_sess_...)","steps":["1. POST /login with {\"email\":\"you@email.com\"}","2. Click magic link in email → get token (pp_sess_...)","3. Use token via CLI, env var, or header"],"tokenMethods":{"cli":"ppod login pp_sess_... (saves to ~/.paperpod/config.json)","envVar":"export PAPERPOD_TOKEN=pp_sess_... (for scripts, CI/CD)","header":"Authorization: Bearer pp_sess_... (per HTTP request)"},"tokenExpiry":"30 days","notes":"New accounts get $5 free credits (~14 hours). Top up via /topup endpoint."},"cli":{"install":"npm install -g @paperpod/cli","commands":{"exec":"ppod exec <cmd> - run shell command","write":"ppod write <path> [file] - write file","read":"ppod read <path> - read file","ls":"ppod ls <path> - list directory","watch":"ppod watch <path> - watch filesystem changes (use /workspace, not workspace)","start":"ppod start <cmd> - start background process","ps":"ppod ps - list processes","kill":"ppod kill <id> - stop process","expose":"ppod expose <port> - get public URL","screenshot":"ppod browser:screenshot <url> - capture webpage","pdf":"ppod browser:pdf <url> - generate PDF","scrape":"ppod browser:scrape <url> [sel] - scrape elements (default: body)","markdown":"ppod browser:markdown <url> - extract markdown","content":"ppod browser:content <url> - get rendered HTML","trace":"ppod browser:trace start|stop - browser tracing (or --trace flag)","test":"ppod test <url> <assertions> - Playwright assertions","browserAcquire":"ppod browser:acquire - acquire reusable session","browserConnect":"ppod browser:connect <id> - connect to existing session","browserSessions":"ppod browser:sessions - list active sessions","browserLimits":"ppod browser:limits - check browser limits","ai":"ppod ai <prompt> - text generation","aiEmbed":"ppod ai:embed <text> - generate embeddings","aiImage":"ppod ai:image <prompt> - generate image","aiTranscribe":"ppod ai:transcribe <file> - transcribe audio","aiModels":"ppod ai:models - list available AI models","interpret":"ppod interpret <code> - rich output (charts)","memWrite":"ppod mem:write <path> - persist data","memRead":"ppod mem:read <path> - read data","memLs":"ppod mem:ls - list files","memRm":"ppod mem:rm <path> - delete file","memUsage":"ppod mem:usage - check quota","balance":"ppod balance - check credits","status":"ppod status - connection info (sandbox, credits, token expiry)","help":"ppod help - show all commands","login":"ppod login <token> - save token to ~/.paperpod/config.json","version":"ppod version - show CLI version"},"update":"npm update -g @paperpod/cli"},"endpoints":{"GET /":{"description":"API schema and discovery (this endpoint)","auth":false,"returns":"JSON schema"},"GET /health":{"description":"Health check","auth":false,"returns":"{ status, timestamp }"},"GET /docs":{"description":"Human-readable documentation","auth":false,"returns":"HTML"},"POST /execute":{"description":"Execute Python or JavaScript code","auth":true,"params":{"code":{"type":"string","required":true},"language":{"type":"string","enum":["python","javascript","shell"],"required":true},"sessionId":{"type":"string","required":false,"description":"Reuse sandbox"},"timeout":{"type":"number","required":false,"default":30000},"env":{"type":"object","required":false}},"returns":"{ status, result: { stdout, stderr, exitCode } }","example":{"code":"print('hello')","language":"python"}},"POST /execute/stream":{"description":"Execute code with streaming output (SSE)","auth":true,"params":"Same as /execute","returns":"Server-Sent Events stream"},"POST /interpret":{"description":"Code interpreter with rich output (charts, images)","auth":true,"params":{"code":{"type":"string","required":true},"language":{"type":"string","enum":["python","javascript"],"default":"python"},"sessionId":{"type":"string","required":false}},"returns":"{ results: [{ type: 'text'|'image'|'error', text?, data?, mimeType? }] }","notes":"Python matplotlib figures captured as base64 PNG"},"POST /files/write":{"description":"Write file to sandbox","auth":true,"params":{"path":{"type":"string","required":true},"content":{"type":"string","required":true},"sessionId":{"type":"string","required":false}}},"POST /files/read":{"description":"Read file from sandbox","auth":true,"params":{"path":{"type":"string","required":true},"sessionId":{"type":"string","required":false}}},"POST /files/list":{"description":"List directory contents","auth":true,"params":{"path":{"type":"string","required":true},"sessionId":{"type":"string","required":false}}},"POST /watch":{"description":"Watch filesystem changes as a Server-Sent Events stream","auth":true,"params":{"path":{"type":"string","required":true,"description":"Use an absolute path like /workspace for now"},"recursive":{"type":"boolean","required":false,"default":true},"include":{"type":"string[]","required":false,"description":"Glob allowlist. Cannot be used together with exclude."},"exclude":{"type":"string[]","required":false,"description":"Glob blocklist. Cannot be used together with include."},"sessionId":{"type":"string","required":false}},"returns":"Server-Sent Events stream of watch lifecycle and file change events","notes":"Use /workspace for now. Passing workspace currently resolves to /workspace/workspace and fails."},"POST /files/mkdir":{"description":"Create directory","auth":true,"params":{"path":{"type":"string","required":true},"sessionId":{"type":"string","required":false}}},"POST /files/upload":{"description":"Upload binary file (multipart/form-data - no base64 encoding needed)","auth":true,"contentType":"multipart/form-data","params":{"file":{"type":"File","required":true,"description":"Binary file to upload"},"path":{"type":"string","required":true,"description":"Destination path in sandbox"}},"returns":"{ success, path, size, originalName, sessionId }","notes":"More efficient than base64 encoding for large binary files like images, audio, video"},"GET /files/download":{"description":"Download file as binary (no base64 encoding)","auth":true,"params":{"path":{"type":"string","required":true,"description":"Query param: ?path=/path/to/file"}},"returns":"Binary file with appropriate Content-Type header","notes":"File extension determines Content-Type. Efficient for media files."},"POST /process/start":{"description":"Start background process (auto-terminates after 15 min, use 'ppod start' CLI for longer)","auth":true,"params":{"command":{"type":"string","required":true},"processId":{"type":"string","required":false},"sessionId":{"type":"string","required":false}}},"POST /process/list":{"description":"List all processes","auth":true,"params":{"sessionId":{"type":"string","required":false}}},"POST /process/get":{"description":"Get process status","auth":true,"params":{"processId":{"type":"string","required":true},"sessionId":{"type":"string","required":false}}},"POST /process/kill":{"description":"Kill a process","auth":true,"params":{"processId":{"type":"string","required":true},"sessionId":{"type":"string","required":false}}},"POST /expose":{"description":"Expose port and get preview URL","auth":true,"params":{"port":{"type":"number","required":true,"description":"1-65535 (avoid 3000-3010 reserved)"},"sessionId":{"type":"string","required":false}},"returns":"{ url, wsUrl, exposedAt }","notes":"Ports 3000-3010 are reserved for system use. Preview URLs are stable across restarts.","urlFormat":"https://{port}-{sessionId}-p{port}_v1.paperpod.work"},"POST /browser/screenshot":{"description":"Capture screenshot of a URL","auth":true,"params":{"url":{"type":"string","required":true},"fullPage":{"type":"boolean","required":false,"default":false},"width":{"type":"number","required":false,"default":1280},"height":{"type":"number","required":false,"default":720}},"returns":"image/png binary","pricing":"$0.0001/second of browser time"},"POST /browser/pdf":{"description":"Generate PDF of a URL","auth":true,"params":{"url":{"type":"string","required":true},"format":{"type":"string","required":false,"default":"A4","options":["A4","Letter","Legal"]},"landscape":{"type":"boolean","required":false,"default":false}},"returns":"application/pdf binary","pricing":"$0.0001/second of browser time"},"POST /browser/markdown":{"description":"Extract markdown content from a URL","auth":true,"params":{"url":{"type":"string","required":true}},"returns":"{ markdown, billing, meta }","pricing":"$0.0001/second of browser time"},"POST /browser/scrape":{"description":"Extract HTML elements from a URL using CSS selector","auth":true,"params":{"url":{"type":"string","required":true},"selector":{"type":"string","required":true}},"returns":"{ data, billing, meta }","pricing":"$0.0001/second of browser time"},"POST /browser/content":{"description":"Get fully rendered HTML content of a URL","auth":true,"params":{"url":{"type":"string","required":true}},"returns":"{ html, billing, meta }","pricing":"$0.0001/second of browser time"},"POST /ai/generate":{"description":"Text generation using LLMs (Llama, Qwen, Mistral, etc.)","auth":true,"params":{"prompt":{"type":"string","required":false,"description":"Text prompt (use this OR messages)"},"messages":{"type":"array","required":false,"description":"Chat messages [{role, content}]"},"model":{"type":"string","required":false,"default":"@cf/meta/llama-3.2-1b-instruct"},"max_tokens":{"type":"number","required":false,"default":1024},"temperature":{"type":"number","required":false,"default":0.7}},"returns":"{ result, model, billing, usage }","pricing":"$0.02 per 1,000 Neurons"},"POST /ai/embed":{"description":"Generate embeddings for text","auth":true,"params":{"text":{"type":"string|array","required":true},"model":{"type":"string","required":false,"default":"@cf/baai/bge-base-en-v1.5"}},"returns":"{ result, model, billing, usage }","pricing":"$0.02 per 1,000 Neurons"},"POST /ai/image":{"description":"Generate images from text prompts (FLUX)","auth":true,"params":{"prompt":{"type":"string","required":true},"model":{"type":"string","required":false,"default":"@cf/black-forest-labs/flux-1-schnell"},"num_steps":{"type":"number","required":false,"default":4},"width":{"type":"number","required":false,"default":1024},"height":{"type":"number","required":false,"default":1024}},"returns":"image/png binary OR { result }","pricing":"$0.02 per 1,000 Neurons"},"POST /ai/transcribe":{"description":"Transcribe audio to text (Whisper)","auth":true,"params":{"audio":{"type":"string","required":true,"description":"Base64 encoded audio"},"model":{"type":"string","required":false,"default":"@cf/openai/whisper"}},"returns":"{ result, model, billing, usage }","pricing":"$0.02 per 1,000 Neurons"},"GET /ai/models":{"description":"List available AI models","auth":false,"returns":"{ models, defaults, pricing }"},"POST /login":{"description":"Login via email magic link OR wallet (MPP zero-dollar identity)","auth":false,"params":{"email":{"type":"string","required":false,"description":"Email for magic link auth (humans)"},"wallet":{"type":"string","required":false,"description":"0x wallet address for zero-dollar MPP identity auth (agents with wallets)"},"Authorization":{"type":"header","required":false,"description":"Authorization: Payment ... on the retry after the MPP challenge"}},"returns":{"email":"{ success, message } - check email for magic link","wallet_no_payment":"402 with WWW-Authenticate: Payment challenge","wallet_with_payment":"{ token, wallet, creditsRemaining } - identity verified, session created"},"notes":"Email: Click magic link → $5 free grant. Wallet: zero-dollar MPP proof auth verifies ownership without transferring funds, then creates a normal PaperPod session.","flows":{"email":"POST {email} → check email → click link → get token","wallet":"POST {wallet} → get 402 → sign zero-dollar proof → POST {wallet} + Authorization: Payment ... → get token"}},"GET /login/callback":{"description":"Magic link callback (handled automatically)","auth":false,"notes":"Redirects to success page with PaperPod token after email verification."},"POST /auth/refresh":{"description":"Refresh a token that is about to expire","auth":false,"params":{"token":{"type":"string","required":true,"description":"Your current PaperPod token (must still be valid)"}},"returns":"{ token, expiresIn, userId }","notes":"Only works if token has < 1 hour remaining AND is still valid. If token is already expired, use POST /login instead.","important":"This endpoint CANNOT revive an expired token. Use POST /login for expired tokens."},"POST /topup":{"description":"Top up credits via MPP using Tempo or Stripe","auth":true,"params":{"tier":{"type":"string","required":false,"description":"Credit package: micro=$1, starter=$5, pro=$20 (+10%), scale=$100 (+20%)"},"amountCents":{"type":"number","required":false,"description":"Custom amount in cents (min 100 = $1)"},"X-Session-Token":{"type":"header","required":true,"description":"PaperPod token used while Authorization is reserved for MPP Payment credentials"}},"returns":{"challenge":"402 Payment Required with WWW-Authenticate: Payment headers for configured methods","success":"{ success, amountCents, creditsAdded, creditsRemaining, paymentMethodsAccepted }"},"notes":"Send {tier} or {amountCents}; the server responds with an MPP challenge and verifies whichever configured payment method the client chooses.","agentInstruction":"Use an MPP-capable client. Send your PaperPod token via X-Session-Token because Authorization is reserved for Payment credentials."},"GET /balance":{"description":"Check current credit balance","auth":true,"returns":"{ creditsRemaining, creditsRemainingUsdc }"},"POST /memory/write":{"description":"Write to persistent Agent Memory","auth":true,"params":{"path":{"type":"string","required":true,"description":"File path (e.g., 'data/results.json')"},"content":{"type":"string","required":true}},"returns":"{ success, size, path }","notes":"Survives sandbox restarts. 10MB quota per user."},"POST /memory/read":{"description":"Read from Agent Memory","auth":true,"params":{"path":{"type":"string","required":true}},"returns":"{ success, content, size }"},"POST /memory/list":{"description":"List files in Agent Memory","auth":true,"params":{"prefix":{"type":"string","required":false}},"returns":"{ success, files: [{ path, size, modified }] }"},"POST /memory/delete":{"description":"Delete file from Agent Memory","auth":true,"params":{"path":{"type":"string","required":true}}},"POST /memory/usage":{"description":"Get Agent Memory usage stats","auth":true,"returns":"{ usedBytes, quotaBytes, fileCount }"},"POST /ws/session":{"deprecated":true,"description":"DEPRECATED - Get WebSocket token","replacement":"Use POST /login to get PaperPod token, then connect to /ws with Authorization: Bearer header","notes":"This endpoint will be removed in a future version."},"GET /ws":{"description":"WebSocket upgrade - persistent bidirectional connection","auth":"Authorization: Bearer <token>","protocol":"JSON messages over WebSocket","discovery":"Send { type: 'help' } for full WebSocket API schema"}},"websocket":{"url":"wss://paperpod.dev/ws","auth":"Authorization: Bearer <token>","messages":["help","ping","exec","interpret","read","write","writeMany","list","process","expose","balance","memory_write","memory_read","memory_list","memory_delete","memory_usage","browser_screenshot","browser_pdf","browser_markdown","browser_scrape","browser_content","ai_generate","ai_embed","ai_image","ai_transcribe"],"discovery":"Send { type: 'help' } after connecting for full WS API schema with all message types and parameters"},"discovery":{"cli":"ppod help - list all CLI commands","http":"GET / returns JSON schema, GET /docs returns HTML docs","skillMd":"GET /SKILL.md or /.well-known/skill.md for Agent Skills format","note":"Run 'ppod help' or 'curl https://paperpod.dev/' before starting"},"pricing":{"model":"Compute & Browser: $0.0001/second. AI: $0.02/1,000 Neurons.","freeCredits":"$5 for new accounts (~14 hours of compute or ~250K AI neurons)","topUp":"MPP top-ups via Tempo or Stripe","tiers":{"micro":"$1 (~3 hours)","starter":"$5 (~14 hours)","pro":"$20 (~61 hours, +10% bonus)","scale":"$100 (~333 hours, +20% bonus)"},"rates":{"compute":"$0.0001/second (code execution, processes)","browser":"$0.0001/second (screenshot, PDF, scrape)","ai":"$0.02/1,000 Neurons (all models)","agentMemory":"Included","previewUrls":"Included","fileIO":"Included"},"newAccountCredits":"$5.00 free for new accounts"},"links":{"docs":"https://paperpod.dev/docs","topup":"https://paperpod.dev/topup","x402":"https://x402.org"},"security":{"browser":{"ssrfProtection":"Internal/private IPs blocked (localhost, 127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x)","protocolValidation":"Only http:// and https:// URLs allowed","maxViewport":{"width":3840,"height":2160,"deviceScaleFactor":3},"maxWaitTimeout":"30 seconds"},"ai":{"maxTextLength":"100K characters (~25K tokens)","maxAudioSize":"25MB","maxImageDimensions":"2048x2048","maxImageSteps":50,"maxLLMTokens":4096}}}