For machines, and the people who run them

Funnelkeeper for AI agents

You build the product; Funnelkeeper is the money layer you read from and propose into. Everything on this page is also in /llms.txt — the short version an agent should fetch first.

How do you install Funnelkeeper?

Machine index https://funnelkeeper.com/llms.txt
API base https://funnelkeeper.fly.dev
API contract https://funnelkeeper.com/openapi.json
MCP server (stdio) npx -y funnelkeeper funnelkeeper-mcp
Executable quickstart https://funnelkeeper.com/docs/quickstart-agents.md

Auth: Authorization: Bearer fk_live_… — an account API key your user mints in the dashboard or with fk login.

What can you do through the MCP endpoint?

funnel.read read
Stage-by-stage counts and conversion rates for a product, filtered by channel and date range. GET /products/{slug}/funnel · MCP get_funnel
payback.read read
Payback day, CAC, LTV and LTV:CAC per channel cohort, plus the curve as a series. GET /products/{slug}/payback · MCP get_payback
spend.read read
Daily spend by channel and campaign, with caps and whether a cap is currently binding. GET /products/{slug}/spend · MCP get_spend
events.log write
Write distribution events you performed — a post shipped, a listing submitted, an email sent. POST /distribution · MCP log_distribution
budget.propose proposal
Propose a spend change with rationale and rollback condition. Queued for a human; never executed by you. POST /products/{slug}/proposals · MCP propose_budget_change

What guarantees can you make to your user?

Human in the loop

You cannot spend money

budget.propose is the only write that touches an ad network, and it returns pending_human. Approval happens in the app, by a person — backed by a database constraint, not a prompt.

Audit log

Every action is on the record

Each call is logged with the acting account, arguments and outcome. The user can read the log and revoke your key from the dashboard.

Server-side caps

Policy caps are not advisory

Caps are enforced at the API boundary. A proposal above the cap is rejected with policy_code: policy_refused rather than escalated to a human.

What does a proposal look like?

The only write that can lead to an ad-network change. It queues; a person decides. This is the live contract — the 202 and 422 below are real responses from the production API.

POST /products/ledgerly/proposals
{
  "network": "meta",
  "campaign_id": "prospecting-us",
  "from_cents": 400,
  "to_cents": 800,
  "rationale": "Cohort from Jul 12 reached payback on day 19 at $58 CAC. Cap binding 6 of last 7 days.",
  "rollback_if": { "cac_usd_above": 80, "window_days": 5 }
}

→ 202 Accepted
{ "proposal_id": "53825372-…", "status": "pending_human", "expires_in_hours": 72 }

→ 422 when over a policy cap
{ "error": "Exceeds product daily cap ($4.00/day for current stage).", "policy_code": "policy_refused" }