Agents welcome here

Honest Pitches treats AI agents as first-class users. If you are a coding agent (Cursor, Claude Code, Codex, etc.) or an autonomous agent acting on behalf of a pitcher — the human who creates pitches on Honest Pitches — you can use the same tools the studio uses, the same way the studio uses them.

Start here: SKILL.md — the agent-native brief for MCP, CLI, and SDK. Fetch it, drop it into your agent's skills folder, or read it before you act. Most agents should begin with this file rather than scraping this HTML page.

Pick the right surface:

All three surfaces share the same hp_pk_… key the user mints in the studio at Settings → API keys; they are interchangeable. The SDK is a thin HTTP client for the MCP; the CLI is a thin argv shim for the SDK; the MCP is the canonical server.

Option 1 — Connect to the hosted MCP server (recommended)

If your client speaks MCP natively (Cursor, Claude Desktop, and most modern coding agents), point it at the hosted Pitch MCP at https://mcp.honestpitches.com/mcp and send the user's key as Authorization: Bearer hp_pk_…. That's the entire setup — no install, no vendor config, no backend URLs to copy.

POST https://mcp.honestpitches.com/mcp
Authorization: Bearer hp_pk_…
Content-Type: application/json
Accept: application/json, text/event-stream

{"jsonrpc":"2.0","id":1,"method":"initialize",
 "params":{"protocolVersion":"2025-03-26",
           "capabilities":{},
           "clientInfo":{"name":"my-agent","version":"1.0"}}}

For interactive clients that ask for a server URL + token pair, the URL is https://mcp.honestpitches.com/mcp and the token is the hp_pk_… key from Settings → API keys in the studio (the same key every surface accepts).

The MCP exposes 12 tools (the same shape the SDK uses), plus an OAuth discovery path for clients that prefer standards-based auth. The list is in the What the agent can do table below.

Option 2 — Use the hp CLI

Shell-using agents (Aider, Codex, a dev terminal) can skip both the MCP registration and the SDK install and use the hp CLI directly. Same auth, same hosted MCP, same PITCHER_API_KEY env var — just one less import to manage in the prompt.

npm install -g @honest-pitches/cli
# then:
export PITCHER_API_KEY=hp_pk_…
hp pitches list

The CLI ships 7 commands (pitches create / get / list / transition / scaffold, plus frameworks list / sections). It's a thin argv shim around the SDK — every command maps 1:1 to an SDK method. Use it as a probe to confirm auth is working, or pipe it into a shell pipeline (hp pitches scaffold ... | hp pitches create --input -).

The CLI is public on npmjs.com as @honest-pitches/cli. The binary name is hp (unchanged from the v0.4.0 era).

Option 3 — For developers: install the Pitch SDK

If you are writing your own integration or want a typed TypeScript surface, install the Pitch SDK. It is a thin HTTP client that talks to the same hosted MCP at https://mcp.honestpitches.com — the SDK never sees a backend URL or any vendor-shaped config.

pnpm add @honest-pitches/pitch-sdk

# Then in your agent's code:
import { createPitcherClient } from "@honest-pitches/pitch-sdk";
const client = createPitcherClient({ apiKey: process.env.PITCHER_API_KEY });
const pitches = await client.pitches.list({ limit: 10 });

That's the entire SDK config — { apiKey } only. The SDK defaults its base URL to https://mcp.honestpitches.com, so the SDK is interchangeable with the MCP and the CLI: every surface shares the same hp_pk_… key.

The SDK is public on npmjs.com as @honest-pitches/pitch-sdk.

Authenticate the user

The user issues a key in their studio at Settings → API keys and pastes it into your environment. You send it as Authorization: Bearer hp_pk_… on every call.

What the agent can do

The hosted Pitch MCP server (https://mcp.honestpitches.com) exposes the full surface as MCP tools; the Pitch SDK exposes the same surface as a typed API; the hp CLI exposes the same surface as shell commands. Pick whichever your agent prefers — they share one tool catalog.

Tool What it does Example payload
list_frameworks Browse the registered pitch frameworks (PAS, AIDA, BAB, FAB, PSS, 4Ps, custom, DRTV classic, DRTV long-form) {}
get_framework Read one framework's full definition (sections, prompts, scoring weights) {"id":"pas"}
get_segment Read one segment (SectionKind) definition by kind {"kind":"problem"}
suggested_sections_for_framework Return empty section stubs for a framework — useful as a starting skeleton {"framework":"pas"}
scaffold_pitch_from_framework Build a draft pitch locally from a framework — no network call, dry-run safe {"framework":"pas","creatorId":"CREATOR_ID","slug":"my-product","title":"My Product","ctaUrl":"https://buy.example/"}
create_pitch Persist a draft pitch for the user (framework locked after preview) {"creatorId":"CREATOR_ID","slug":"my-product","title":"My Product","framework":"pas","sections":[{"kind":"problem","body":"...","mediaIds":[]},{"kind":"agitate","body":"...","mediaIds":[]},{"kind":"solution","body":"...","mediaIds":[]}],"ctaUrl":"https://buy.example/"}
get_pitch Fetch a pitch by id {"id":"PITCH_ID"}
list_pitches List the user's pitches with optional status filter {"status":"draft","limit":10}
list_pitch_media List every media asset for a pitch: uploaded `pitch_assets` rows AND auto-generated IDs that live on the pitch row itself (`thumbnailFileId`, `ogImageFileId`). Each result carries a `source: "pitch_assets" | "pitch_row"` discriminator so callers can tell them apart. {"id":"PITCH_ID"}
update_pitch Update a draft pitch (framework locked after preview) {"id":"PITCH_ID","title":"Updated title"}
transition_pitch_status Move a pitch through its lifecycle. Returns `lifecycle` (computed: draft | preview | live | expired | archived) AND `status` (raw row-level: draft | pending_payment | live | expired | removed). Branch on `lifecycle` for terminal-state checks; `lifecycle === "archived"` is the canonical archive check (`status` reads `"removed"`). {"id":"PITCH_ID","to":"preview"}
get_my_creator Resolve the caller's creators row id from the authenticated user — returns null if the user has no creator row yet {}

Need the long-form MCP setup (OAuth discovery, dynamic client registration, the request/response framing conventions)? The .well-known/oauth-protected-resource document is the canonical answer; your MCP client will fetch it automatically if it follows RFC 8707.

Status vs lifecycle (the source-of-truth distinction)

The transition_pitch_status tool returns TWO fields on every pitch row. Both describe the same row but answer different questions:

lifecycle (computed, branch on this) status (row-level, persisted) Notes
draftdraftNo previewToken on the row.
previewdraftpreviewToken is present; the row is previewable but not yet live.
liveliveThe published state. visibility may still be unlisted.
expiredexpiredTime-boxed lapses; same word on both sides.
archivedremovedIntentional rename: branch on lifecycle for the terminal check. status: "removed" is the raw equivalent.

Rule of thumb: branch on lifecycle for any terminal-state check (especially “is this row archived?”). status === "live" is fine for the live-only check; status === "removed" is the raw equivalent of lifecycle === "archived" and they will always agree on the same row.

Archived → preview, archived → draft (the token gate)

Unarchiving an archived row is token-gated: the request must include a previewToken, the same token issued the first time the row was moved to preview. Without it the server returns 400 previewToken is required to unarchive (mirrors draft → preview, which has the same gate).

Where the token comes from:

Not supported: archived → preview in a single step. The supported paths are archived → draft (token required) and then draft → preview (which may issue a NEW previewToken if one was already on the row).