Quickstart

Two ways in: connect the MCP server to an agent you already have, or call the API directly. Both run the same engine under the same budget and billing rules.

All you need first is a Frames account — sign up at https://frames.ag. Every new account starts on the Free plan (3,000 credits/month, paid tools included, no card). Upgrading to a paid tier (Starter / Pro / Ultra) happens in Billing via Stripe Checkout. Runs are authorized against your plan and your credit balance; 1 credit = $0.001.

1. MCP — for an existing agent

No API keys to manage or configure. Add the Frames MCP server URL to your client (Claude, ChatGPT, Cursor, or any remote-MCP-capable host) and authenticate with your Frames account:

https://api.frames.ag/mcp

Your client registers itself and opens the Frames OAuth flow in the browser: sign in to your Frames account (if you aren't already) and click Approve. The connection is bound to your account's workspace, so every tool call runs under your plan, budget, and credit balance. No anonymous paid execution.

You get the delegation tool, the free discovery surface, and three reads:

| Tool | What it does | |---|---| | frames_run_capability | Delegation: { task, max_usd?, output_schema? } → a full bounded run (plan → buy tools → execute → verify) returning { run_id, status, billing, result, usage, receipts, confidence }. A long run returns { run_id, status: "running" } — poll frames_get_run. | | frames_search_tools | FREE. Search the ~37k-tool paid catalog by intent (2–4 angles in parallel). Confident top hits come back invoke-ready: probe-verified live, real price_usd, the seller's actual input_schema. Returns a search_id. | | frames_get_tool | FREE. Full catalog descriptor for one tool id. | | frames_probe_tools | FREE. Probe up to 5 candidates at once, unpaid: liveness, price quote, real arg schema. Rate-limited per project per hour. | | frames_get_run | Fetch a run by id (project-scoped). | | frames_get_receipt | The payment receipts for one run. | | frames_get_usage | Your project's credit balance, available credits, and open reserve holds. |

Your own model orchestrates: search (free) → the invoke_ready hit already carries the exact args schema → act on it. Probe explicitly only for candidates search didn't pre-verify.

Headless agents (no browser)

Frameworks and scripts that can't drive interactive OAuth authenticate with a Frames API key directly — the same fk_… key the API uses, sent as a bearer on /mcp:

# any MCP client that supports static headers
Authorization: Bearer fk_YOUR_KEY

Copy-paste installs:

# Claude Code
claude mcp add --transport http frames https://api.frames.ag/mcp
# headless (API key, no browser):
claude mcp add --transport http frames https://api.frames.ag/mcp \
  --header "Authorization: Bearer fk_YOUR_KEY"
// Claude Desktop / Cursor (mcpServers config)
{ "mcpServers": { "frames": { "url": "https://api.frames.ag/mcp" } } }
# stdio-only clients — bridge with mcp-remote
npx mcp-remote https://api.frames.ag/mcp

Agents that don't speak MCP at all get the same discovery surface as plain REST — see “Tool discovery over REST” below.

2. Tool discovery over REST

The MCP discovery tools have REST twins (same auth as /v1, same JSON shapes) for function-calling agents in any framework:

curl -X POST https://api.frames.ag/v1/tools/search \
  -H "Authorization: Bearer fk_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"queries":["twitter user info","tweet history"]}'
# → { "search_id": "srch_…", "hits": [ { "id", "title", "payment", "invoke_ready", "price_usd", "input_schema", … } ] }

curl -X POST https://api.frames.ag/v1/tools/probe \ -H "Authorization: Bearer fk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"ids":["frames.twitter.post.api-user-info"]}' ```

Machine-readable definitions (import as native tool defs in any function-calling framework): GET /v1/tools/spec.

3. API — direct task execution

For programmatic access (your own code, OpenAI SDKs), create an API key in the dashboard under Developers → API access. Keys look like fk_… and the plaintext is shown once — store it.

Native: POST /v1/runs

curl https://api.frames.ag/v1/runs \
  -H "Authorization: Bearer fk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-unique-key-001" \
  -d '{
    "task": "Research 3 companies that may use x402, return evidence URLs",
    "budget": { "max_usd": 3 },
    "options": { "verification": "standard" }
  }'

Request fields (see src/run/create-run.ts):

Send Accept: text/event-stream to stream over SSE — answer tokens flush live as the model generates them (with tool/progress as reasoning deltas), not as a buffered dump. Fetch any run later with GET /v1/runs/:id (same auth; runs are project-scoped).

If your budget exceeds what the project's policy allows, the run is created paused and returned with HTTP 402 and status: "requires_approval" (no credits held). Resume the same run with POST /v1/runs/:id/approve { "max_usd": <number> } — the approved budget is still capped at your plan's per-run maximum — or drop it with POST /v1/runs/:id/cancel.

Other errors come back as a typed envelope { "error": { "type", "message", "code", "request_id" } } — notably 402 insufficient_credits and 403 no_subscription.

OpenAI-compatible: /v1/chat/completions and /v1/responses

Point an OpenAI SDK at the gateway and pass budget/verification in the frames extension field (see src/routes/openai-shim.ts). Using the Vercel AI SDK? See docs/ai-sdk.mdcreateOpenAICompatible + generateText / generateObject work against this surface as-is.

curl https://api.frames.ag/v1/chat/completions \
  -H "Authorization: Bearer fk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "frames-pro",
    "messages": [{ "role": "user", "content": "Find the current USDC supply on Base, with a source" }],
    "frames": { "budget_usd": 1, "verification": "standard" }
  }'

POST /v1/responses is the same shim over the Responses shape (input, instructions, text.format), with the same frames extension. Both surfaces return standard OpenAI usage plus frames_usage (the truth) and frames: { run_id, status, confidence }, so you can always pull the full run.

4. What you get back

Every run returns the answer and the accounting:

Project-level aggregates (balance, spend breakdown, undelivered-payment count) are in the dashboard, or GET /api/usage?project_id=… with a dashboard session.