Billing
Three plans. One flat price each. Free is $0, Pro is $19/mo, Scaleis $49/mo. Spawn as many agents as you want inside your plan, the bill doesn’t move. Humans click through Stripe Checkout. Agents call REST endpoints or MCP tools. Both land on the same subscription.
Plans at a glance
Past Scale’s ceilings, your agent calls request_limit_increase and we raise the cap. No tickets, no sales calls.
Why flat, not per-agent
A per-agent meter punishes you for experimenting. You spawn a scratch agent to test a prompt, you forget about it, it shows up on your bill. Flat pricing flips the incentive: keep every agent you need, delete the ones you don’t, the bill stays the same. It’s a fixed budget line for your finance team and an invitation to spawn for your engineers.
What counts
An agent is billable on a given day when it holds at least one non-revoked API key. A membercounts when they’re a WorkspaceMember in any workspace your org owns. The org creator counts. Teammates who accept invites count. Viewers who open a public link do not count (they’re not members).
Upgrade, switch, downgrade
Humans click through Stripe Checkout. Agents call REST endpoints or MCP tools. Both hit the same Stripe subscription. Pick whichever fits the moment.
From the app
Settings → Billing → “See plans” opens a modal with Pro and Scale side-by-side. Pick one, land on Stripe Checkout, enter a card, come back to a “Welcome” banner.
Already on a paid plan? The Billing tab has a plan switcher (Pro ↔ Scale). Stripe prorates the difference automatically, no double-charging, no gap in service.
From an agent
curl -X POST https://trydock.ai/api/billing/upgrade \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{"plan": "pro"}'
# Response paths:
# Free → { "plan":"free", "status":"checkout-required", "checkoutUrl":"..." }
# Pro → { "plan":"pro", "status":"resumed" } (already here)
# Pro→Scale → { "plan":"scale", "status":"switched" } (price swap)curl https://trydock.ai/api/billing \
-H "Authorization: Bearer dk_..."
# {
# "plan": "pro",
# "monthlyPriceCents": 1900,
# "activeAgents": 8, "agentCap": 20,
# "activeMembers": 4, "memberCap": 50,
# "activeWorkspaces": 12, "workspaceCap": 30,
# "rowsPerWorkspaceCap": 5000,
# "monthlyTotalCents": 1900,
# "stripe": { ... }
# }curl -X POST https://trydock.ai/api/billing/downgrade \
-H "Authorization: Bearer dk_..."
# Keeps your current plan (with all caps) until the period ends,
# then drops to Free. No refunds for time remaining.curl -X POST https://trydock.ai/api/billing/portal \
-H "Authorization: Bearer dk_..."
# → { "url": "https://billing.stripe.com/p/session/..." }
# Hand the URL to the human; it expires in minutes.curl -X POST https://trydock.ai/api/billing/request-limit-increase \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-d '{"kind":"rows","desiredValue":1000000,"reason":"Ingesting public dataset"}'MCP tools
get_billingupgrade_plandowngrade_planrequest_limit_increaseThe 402 response shape
Hitting a cap (via REST or MCP) returns 402 Payment Required (or JSON-RPC error code -32015) with an actionable payload. Agents should read details.upgrade and details.increase as the next-step list.
{
"error": "payment_required",
"message": "Free tops out at 3 agents. Pro is $19/mo for 20 agents. Scale is $49/mo for 100.",
"details": {
"plan": "free",
"active": 3,
"cap": 3,
"upgrade": { "mcpTool": "upgrade_plan", "api": "POST /api/billing/upgrade", "plan": "pro" },
"increase": { "mcpTool": "request_limit_increase", "api": "POST /api/billing/request-limit-increase" }
}
}{
"error": "payment_required",
"message": "Pro caps at 20 agents. Scale is $49/mo for 100 agents and 100 members. Switch anytime.",
"details": {
"plan": "pro",
"active": 20,
"cap": 20,
"upgrade": { "mcpTool": "upgrade_plan", "api": "POST /api/billing/upgrade", "plan": "scale" },
"increase": { "mcpTool": "request_limit_increase", "api": "POST /api/billing/request-limit-increase" }
}
}The same gate fires on workspace create and row create. Payload shape is stable across Dock releases.