# PitchStation > PitchStation turns any document into a secure, tracked share link that answers back: viewers can ask the document questions (AI Q&A grounded in its content), and the owner gets per-page analytics with an AI readout. It also generates documents (pitch decks, reports, IR letters, brand kits, small-business websites) from prompts, repos, or brochures. PitchStation exposes an MCP server so AI agents (Claude Code, Cline, Continue, any MCP host) can publish and manage tracked share links directly. ## Connect an AI agent (MCP) - START HERE if you are an agent asked to set yourself up: https://staging.pitchstation.ai/ai-skill-setup.md — the complete setup guide (token, install, default configuration, verification), written for you. Its human/shareable twin is https://staging.pitchstation.ai/ai-skill-setup.html — that is the URL to send to someone who wants their AI connected. - Download the MCP server (single Node 18+ file, no dependencies): https://staging.pitchstation.ai/downloads/pitchstation-mcp-server.js - Download the Claude Code skill (SKILL.md): https://staging.pitchstation.ai/downloads/publish-to-pitchstation-SKILL.md - Authentication: a Personal Access Token (pst_...) created by the user at https://staging.pitchstation.ai/tokens.html (shown once; sent as PITCHSTATION_TOKEN env var to the MCP server, or as "Authorization: Bearer " on direct API calls). - Register with an MCP host: command "node /absolute/path/to/pitchstation-mcp-server.js" with env PITCHSTATION_URL=https://staging.pitchstation.ai and PITCHSTATION_TOKEN=. - Install the skill: save SKILL.md to ~/.claude/skills/publish-to-pitchstation/SKILL.md and restart the agent. - No MCP host, or no Node? The PORTABLE skill needs only python3: https://staging.pitchstation.ai/downloads/share-to-pitchstation-SKILL.md and https://staging.pitchstation.ai/downloads/pitchstation.py Save both to ~/.claude/skills/share-to-pitchstation/, put PITCHSTATION_URL and PITCHSTATION_TOKEN in a .env beside them, and run: python3 pitchstation.py publish deck.pdf --team design - Human-readable setup guide with copy-paste commands: https://staging.pitchstation.ai/tutorial.html ## If you are ChatGPT, or any assistant WITHOUT shell/network access - Do NOT attempt to call the API from a ChatGPT sandbox — it has no network at all, and the browsing tool cannot send an Authorization header. Do not loop retrying; nothing will get through. - The working route for ChatGPT is a custom GPT ACTION: import https://staging.pitchstation.ai/api/openapi-shares.json (Actions → Import from URL), auth = API Key, Bearer, the user's pst_ token. Setup steps: https://staging.pitchstation.ai/ai-skill-setup.md (section "Route C"). - Without an Action, hand off instead: save the finished HTML as a downloadable file and give the user (a) the Share composer at https://staging.pitchstation.ai/?share=1 to drag it into, or (b) this command with THEIR token in the environment (never paste a real token into chat): curl -X POST "https://staging.pitchstation.ai/api/share?title=My+Report&access=link&expires=10d&password=auto" \ -H "Authorization: Bearer $PITCHSTATION_TOKEN" -H "Content-Type: text/html" --data-binary @report.html - That raw-body form (Content-Type: text/html, controls as query params: title, access, expires, password, max_views, watermark, downloads, recipients) needs no JSON escaping and is the most reliable thing a constrained assistant can prepare. - BROWSER-PAGE route (works from a ChatGPT canvas/artifact, or any HTML file the user opens): a page you generate may fetch() this API directly from the USER'S browser — the API sends "Access-Control-Allow-Origin: *" for any request carrying "Authorization: Bearer ", so cross-origin POST /api/share works from any origin. Put a password-type input for the token (never hardcode one), POST { htmlContent, title, access, expires_in }, and show the returned url. Cookies are never attached to these calls, so nothing can ride a signed-in session. ## OpenAPI specs (importable as GPT Actions / any tool-calling framework) - https://staging.pitchstation.ai/api/openapi-shares.json — publish, list, edit, replace, revoke, recipients, invite, people (the core share API; /api/contacts = everyone the user has shared with — resolve a name to an address before sharing or invoicing) - https://staging.pitchstation.ai/api/openapi-invoices.json — invoices - https://staging.pitchstation.ai/api/openapi-websites.json — website generation - https://staging.pitchstation.ai/api/openapi-apps.json — app hosting (deploy containerised prototypes to a live URL) - https://staging.pitchstation.ai/api/openapi-devboxes.json — dev instances (reserve and govern repo-sized cloud workbenches for AI coding agents) ## MCP tools - pitchstation_publish: publish HTML/PDF/Office/Markdown content (or a multi-file bundle via files:[]) and get a /s/ tracked URL. Controls: access (link|account|recipient), viewers (account mode: emails/usernames — allowlist + auto-email with the password included when protected), expires_in, max_views, password, watermark, downloads, require_name, allow_forward. - pitchstation_list: list shares owned by the token's user. - pitchstation_replace: update an already-shared document in place (same URL and analytics) — use instead of re-publishing. - pitchstation_revoke: kill a share by slug. - pitchstation_space_create / pitchstation_space_add / pitchstation_space_list: SPACES are branded, tracked collections of existing shares behind one /space/ URL (deal room, client hub, portfolio). Use a space when the document set evolves; use a files:[] bundle for a frozen snapshot. Documents stay live inside a space (replace updates them everywhere); recipient-mode shares cannot join. - pitchstation_invoice_create: create an INVOICE (items in integer cents) and optionally SEND it in the same call — assigns the gap-free number, mints the tracked link, emails the client (password included for external clients; account-locked link when their email matches an account). Chase it at /invoices.html or the /m/invoices/ mobile app. Requires the create.invoice capability. - pitchstation_expense_create: create an EXPENSE PACK (receipts for a trip/project). Upload receipt photos + AI-itemize them in the web app (/expenses.html), producing one approvable tracked link (report + receipt scans as a bundle; approver taps Approve / Request changes on the page). Requires the create.expense capability. ## Direct HTTP API (same capabilities as MCP) - POST https://staging.pitchstation.ai/api/share — create a share. Body: { htmlContent | pdfBase64 | files:[...], title, access, expires_in, password, max_views, ... }. Returns { share: { slug, url, ... } }. - GET https://staging.pitchstation.ai/api/share — list your shares (includes full url per share). - PATCH https://staging.pitchstation.ai/api/share/:slug — edit controls (password, expiry, max_views, require_name, ai_chat_enabled...). - POST https://staging.pitchstation.ai/api/share/:slug/replace — replace content, keep URL + analytics. - POST https://staging.pitchstation.ai/api/share/:slug/revoke — stop the link (reversible; /unrevoke restores it). This is what "revoke" means. - DELETE https://staging.pitchstation.ai/api/share/:slug — DELETE PERMANENTLY (share, analytics, recipients, versions, content). Not the same as revoke. - POST https://staging.pitchstation.ai/api/spaces — create a space { title, description?, access?, password?, expires_in?, require_name? }. GET lists yours; POST /api/spaces/:slug/items { shareSlug, section? } adds a document; GET /api/spaces/:slug/analytics returns the visitor × document matrix. - WEBSITE CREATION (requires the create.website capability — publisher/creator roles have it): - POST https://staging.pitchstation.ai/api/website/extract — multipart: field "pdf" (one brochure PDF) or "file" (up to 6 brochure photos, or ONE .txt/.md file); OR a JSON body { text: "company description (40-24,000 chars)", lang? } → { content, images (logo/hero candidates; [] for text), warnings }. AI drafts the content model from any of the four forms. - POST https://staging.pitchstation.ai/api/website/generate — { content: { meta: { company_name, ... }, hero, services, faq, contact, ... }, assets: { logo: , hero? } } → { deckId, previewUrl }. Renders a complete site (llms.txt + sitemap + robots included). MULTI-PAGE: content.meta.pages = [{slug,title,sections[]}] (slug "" = index, ≤8 pages) renders one static file per page with shared nav; absent = single page. FAST PATH: pass { brief: "text description", lang?, meta_overrides? } instead of content — the server AI-drafts the model and renders in one call, echoing the draft + warnings; external_ref replay is checked before drafting so retries are free. Optional preset: "agent"|"electronics"|"jewelry"|"fashion" expands server-side (your values win). Content identical to another of your sites → warnings[{code:"DUPLICATE_CONTENT"}]. - Partner self-service: POST /api/website/base-domain { domain } → TXT + wildcard-A records → POST /base-domain/verify → sites publish as .. PUT /api/website/brand-tokens { accent, ink, paper, font_pair, radius } → your (locked) template re-skins with validated token values on next regenerate. - GET https://staging.pitchstation.ai/api/website/list — your sites with reviewStatus/round. POST /api/website/:deckId/update — save content + regenerate in place (same links). - POST https://staging.pitchstation.ai/api/website/:deckId/submit-review — { approverEmail?, password?, expiresIn? } → customer review link (approve / request-changes on the page); approverEmail auto-emails the link with the password included. GET /api/website/:deckId/review — status, round, history, reviewUrl. - GET https://staging.pitchstation.ai/api/website/:deckId/bundle — deployable .zip of the site. - APP HOSTING (requires the app.deploy capability — explicit grant only, admins have it; ask the server admin): - Deploy a CONTAINERISED PROTOTYPE (any project with a docker-compose.yml) to a registered VPS and get a live TLS URL at .apps. — optionally behind a basic-auth preview gate for client review. The platform never runs your code; it orchestrates a host you registered. - GET https://staging.pitchstation.ai/api/apps/targets — container-runtime hosts. PUT /api/apps/targets/:id/runtime { runtime:"container", maxApps, cpuCores, memMb } promotes an existing website deploy target. - POST https://staging.pitchstation.ai/api/apps — { slug, name, targetId, webService, containerPort, healthPath, migrateCmd?, env? } → app with a permanently allocated hostPort. env is stored ENCRYPTED; the API returns key names only, never values. PUT /api/apps/:id/env replaces it. - POST https://staging.pitchstation.ai/api/apps/:id/deploy — { tarballBase64, releaseTs?, note?, previewPassword?, expected?, dryRun }. DRY RUN BY DEFAULT: returns a redacted plan; dryRun:false requires live authorization. Source limits: 80 MiB compressed / 256 MiB expanded / 20,000 entries; links, traversal and known secrets are rejected. Container/data state can change before route activation: never assume a failed health check leaves the prior runtime untouched. - MANAGED PUBLISHING: GET /api/apps/publishing-capabilities, then the owned app's domain-config. Production checkpoint 2026-09-18: pilot enabled for existing target 4 / six apps; custom TXT proof and first managed tenant-route adoption still pending. Do not assume every target/account is enabled. Managed apps persist hosts/gates when redeploy omits them. GET/PUT /:id/domain-config and PATCH /:id/publication-policy use reviewed dry-run plans, If-Match and Idempotency-Key; no build/release/container restart. Plans expire after 15 minutes. Legacy apps require verified inventory; unsupported adapters remain on the old rail. - DOMAIN OWNERSHIP: each custom hostname needs its own _pitchstation. TXT proof from plan/config. Keep correct A/CNAME routing; working TLS is not proof. POST /:id/domain-config/verify checks current or planId domains. No provider DNS writes. Apply the reviewed planId with dryRun:false, its exact If-Match and a stable Idempotency-Key. A saved plan / accepted 202 is not an applied or ready publication. - Add Prefer: respond-async + Idempotency-Key to managed deploy/rollback for a durable 202 operation/statusUrl. Poll GET /:id/operations/:operationId; reconnect with the same key/body. Omit Prefer for the legacy final 200/502 envelope. Unknown SSH/migration outcomes require operator reconciliation, not blind retry. - GET/POST /:id/readiness checks public DNS/TLS/policy/identity/assets, not 3D/video interaction. GET /:id/publication-receipt excludes passwords. PATCH /:id/env set/unset requires If-Match, previews by default, and applying with an Idempotency-Key restarts the current release; PUT env is replace-all/stored-only. The Go-live UI is /apps.html; the official CLI is scripts/pitchstation-apps.cjs (requires the generator checkout/dependencies, not just a downloaded skill). Apps have NO MCP tools. - POLICY: preserve existing passwords/expiry unless explicitly requested. Private passwords are 12–72 UTF-8 bytes; omit password to retain, never send empty. Omit expiresAt to retain; null explicitly removes platform expiry. Public removes only the platform gate, not app-managed login/expiry. Document-share audience/password/30-day defaults do not apply automatically to hosted apps. APP_ACME_EMAIL does not enable expiry alerts: Let's Encrypt ended those emails; platform monitoring/email were off at the 2026-09-18 checkpoint. - POST https://staging.pitchstation.ai/api/apps/:id/rollback — compose up from a retained release, health-checked. Managed rollback keeps hosts/policy and last applied env. Code only: a migration the abandoned release ran is still applied. - POST https://staging.pitchstation.ai/api/apps/:id/preview — one-time { previewUrl, credential }, NOT gate activation. Use publication-policy plan/apply for an existing managed app without rebuilding. A private first deploy can use previewPassword in the protected REST body (CLI deploy has no password flag). POST /:id/stop parks the app (volumes kept). DELETE /api/apps/:id forgets it in the control plane WITHOUT touching the host or freeing live claims. - Releases are directories; the compose project is per-app (ps-), so named volumes — your database — survive every release. - SKILL for agents: https://staging.pitchstation.ai/downloads/create-pitchstation-app-SKILL.md — scaffold/retrofit, deploy content, or change existing domains/policy/env through CLI/REST. Preparing a project does not authorize a live deploy; configuration-only requests must not trigger content builds. Save to ~/.claude/skills/create-pitchstation-app/SKILL.md. - DEV INSTANCES (requires the devbox.manage capability — explicit grant only, admins have it): - A dev instance is a cloud workbench sized for ONE repository with Claude Code / Kimi CLI / Codex pre-installed. PitchStation is the registry and policy engine only: it never makes a cloud call and holds no login credential for any box. The operator's machine provisions (AWS, scoped IAM profile); each box pushes its own telemetry and stops itself when idle. - GET https://staging.pitchstation.ai/api/devboxes/sizes — classes S/M/L/XL with ALL-IN monthly prices (compute + storage + public IPv4, running and stopped) and the pricing version. GET /api/devboxes/agents — pinned agent versions + login hints. - POST https://staging.pitchstation.ai/api/devboxes — RESERVE first: { name, sizeClass, arch?, agents:["claude"|"kimi"|"codex"], repo?:{url,branch}, idleMinutes?, autoscale? }. Checks name uniqueness and your monthly cost cap (402 COST_CAP with the numbers) BEFORE anything exists in the cloud. Then run: scripts/provision-aws-instance.sh --kind devbox --reservation on the operator machine — it fetches GET /:id/bootstrap (secret-free cloud-init), launches, calls POST /:id/provisioning, POST /:id/token (shown once), installs the token over SSH, POST /:id/finalize. - GET https://staging.pitchstation.ai/api/devboxes — yours + team-shared, with cost-to-date. PATCH /:id { idleMinutes, autoscale } (never name, never the cap). PUT /:id/repo, PUT /:id/env (key names only in responses). - Lifecycle confirmations after the operator's AWS call: POST /:id/started | stopped | resizing | resized | renamed | terminated — compare-and-set on the row version, replay-safe with an Idempotency-Key header. DELETE /:id tombstones and is refused while an instance is attached and not terminated. - Telemetry: the box POSTs /:id/report every 5 min with its report token; the response carries the current policy, so a PATCH takes effect within one interval. - POST https://staging.pitchstation.ai/api/devboxes/size — { profile (from scan.py), concurrency?, arch?, override?:{sizeClass}, measured?:{peakRssGb} } → class, all-in price, reasons. One pure function; the CLI and UI both call it. - SKILL for agents: https://staging.pitchstation.ai/downloads/pitchstation-devbox-SKILL.md (+ -devbox.py, -scan.py) — "open a dev box for this repo": size → confirm → reserve → provision → git push; start/stop/resize/grow/terminate/reconcile verbs; five contract rules. Save to ~/.claude/skills/pitchstation-devbox/. - INVOICES (requires the create.invoice capability): - POST https://staging.pitchstation.ai/api/invoices — create a draft { client_name, client_email, client_company?, currency, due_date?, terms?, items:[{description, qty, unit_cents}], tax_label?, tax_cents?, discount_cents?, notes? }. Money is integer cents. - POST https://staging.pitchstation.ai/api/invoices/:id/send — assigns the gap-free number, mints the tracked link, and emails the client (password included for external clients; account-scoped when their email matches an account). Returns { number, url, password?, emailedTo }. - POST https://staging.pitchstation.ai/api/invoices/draft — { description } → AI-drafted fields/items (amounts never invented; nulls when unstated). - GET https://staging.pitchstation.ai/api/invoices (+ aging), GET /:id (+ events), PATCH /:id (drafts free; sent = revision on the same link; paid/partial locked — use POST /:id/credit-note), POST /:id/payments { amount_cents?, method?, reference? } (blank amount = full balance; auto-paid + receipt email), POST /:id/void, POST /:id/remind, POST /:id/duplicate. - GET/POST https://staging.pitchstation.ai/api/invoices/settings — numbering prefix + payment profiles (bank/FPS/PayNow/QR/link) rendered in the invoice's "How to pay" section. - POST https://staging.pitchstation.ai/api/invoices/extract-contract (multipart pdf|file) — contract/SOW → client + items + milestone schedule. POST /api/invoices/chat { messages, draft } → { reply, draft } for conversational drafting. POST /api/invoices/:id/recurrence { day_of_month, auto_send } for monthly retainers (GET /recurrences, DELETE /recurrences/:rid). - Client signals (no auth; link-token gated): POST /s/:slug/invoice/paid-claim { reference? } and /s/:slug/invoice/question { note } — claims stay unconfirmed until the owner confirms (POST /api/invoices/:id/payments/:pid/confirm). - Mobile chase app (installable PWA): https://staging.pitchstation.ai/m/invoices/ — overdue-first list, claim confirm, remind, mark-paid, push deep links. GET /api/invoices/attention-count powers its badge; GET /api/invoices/metrics (admin) returns the go/kill readout (loop-closure %, sent→viewed/viewed→paid medians, reminder conversion, mode mix). - All authenticated with "Authorization: Bearer ". ## Key pages - https://staging.pitchstation.ai/ : product landing - https://staging.pitchstation.ai/login.html : sign in / create account (Google sign-in provisions instantly) - https://staging.pitchstation.ai/tokens.html : create Personal Access Tokens (requires sign-in) - https://staging.pitchstation.ai/tutorial.html : full setup tutorial (bundles, MCP, skills) - https://staging.pitchstation.ai/ai-skill-setup.html : connect YOUR AI to PitchStation — token, skill install (portable python or MCP), default configuration, smoke test — public, no sign-in. Safe to hand to anyone; paste the URL into an assistant and it installs itself. - https://staging.pitchstation.ai/privacy.html and https://staging.pitchstation.ai/terms.html : legal - https://staging.pitchstation.ai/ai-review-guide.html : how a RECIPIENT (or their AI agent) reviews a shared document — public, no sign-in - https://staging.pitchstation.ai/contract-signing-guide.html : the full contract lifecycle — publish, review, revise, sign, executed PDF — public, no sign-in - https://staging.pitchstation.ai/how-to-sign.html : for the SIGNER — what happens when you are asked to sign, what is recorded, how to decline — public, no sign-in - https://staging.pitchstation.ai/teams-guide.html : share a document with a TEAM — create, add members, widen an existing share — public, no sign-in - POST https://staging.pitchstation.ai/api/teams, GET /api/teams, POST /api/teams/:id/members : create a team, list yours, add a member (by confirmed email or username; they need an account). Share with one by passing teams:["handle"] on publish, or PATCH /api/share/:slug/access with addTeams to widen a live share. An ambiguous handle returns 409 TEAM_AMBIGUOUS with candidates — surface them and ask; never choose one. Publishing to a team EMAILS every member automatically (notifyTeams:false opts out); widening an existing share is silent unless you pass notify:true. POST /api/share/:slug/notify {to:"members"|"owner"|"recipients"|[...]} re-sends the notification afterwards; there is no everyone default. - https://staging.pitchstation.ai/ai-review-guide.md, https://staging.pitchstation.ai/tutorial.md and https://staging.pitchstation.ai/ai-skill-setup.md : the same guides as MARKDOWN — fetch these instead of the .html when you are an agent (same content, ~10x fewer tokens; add ?lang=zh for Chinese) ## Notes for agents - Share URLs look like https://staging.pitchstation.ai/s/?k=. The k token is part of the credential — always give the user the complete URL. - If your user was SENT a share link to review: comment-enabled shares are self-describing — fetch the share URL and follow the "AI/LLM agents" note in its HTML to GET /s//review-guide, which documents the comment API (anchored comments, suggested edits, pins). - Re-publishing the same document creates a duplicate link and splits analytics; prefer pitchstation_replace. - Payload cap is 10 MB; strip or compress embedded base64 images if you hit HTTP 413.