Billing and Plans
Most of what follows is for a human at the dashboard, not for an agent:
POST /v1/billing/checkout, POST /v1/billing/portal, POST /v1/billing/addons/*,
and POST /v1/team/* all require a signed-in dashboard session (a browser cookie) —
an MCP agent's API key cannot call them. The one billing endpoint an agent can call
directly is GET /v1/usage, which accepts either a session or an API key. Upgrading,
paying, and inviting teammates all have to happen through the dashboard UI.
Plan comparison
| Feature | Free | Solo | Studio | Agency |
|---|---|---|---|---|
| Monthly price | $0 | $29 | $50 | $79 |
| Active intakes | 1 | 15 | 30 | 60 |
| Items per intake | 10 | Unlimited | Unlimited | Unlimited |
| Seats | 1 | 1 | 1 | 3 |
| Storage | 1 GB | 25 GB | 50 GB | 100 GB |
| API rate limit | 60 req/h | 600 req/h | 1,500 req/h | 3,000 req/h |
| Secrets vault | No | Yes | Yes | Yes |
| Item revisions | No | Yes | Yes | Yes |
| Custom branding | "Powered by BriefGate" + referral link | Your logo + colors, no referral link | + Custom portal domain | + Custom portal domain |
| Custom sending domain | No | No | Yes | Yes |
| Chase schedules | default, off | All (gentle/default/aggressive/custom/off) | All | All |
| Templates | 3 public | 3 public + custom | 3 public + custom | 3 public + custom + team-shared |
| Support | Community | Email, 48h | Priority email, 24h | Priority email, 24h |
| Annual billing | — | $23.20/mo (–20%) | $40/mo (–20%) | $63.20/mo (–20%) |
Annual billing is charged as a single upfront payment. The per-month figures above show the effective monthly cost.
Studio is for one person who needs the agency features — own domain, priority support — without paying for seats. It carries every Agency capability except extra seats and the larger quotas: both custom domains are available, and support gets the same 24h priority target.
Add-ons
| Add-on | Price | Plan |
|---|---|---|
| Extra storage | +50 GB for $5/month | Solo, Studio, Agency |
| Additional Agency seat | +$15/seat/month | Agency |
| SMS credit pack | 50 SMS credits per pack | Studio, Agency |
Changing extra storage
Storage renews with the plan, so it is a line item on the existing subscription rather than a separate purchase. Set how many 50 GB blocks you want:
POST /v1/billing/addons/storage{ "blocks": 2 }The change applies immediately and Stripe prorates it. { "blocks": 0 } removes the add-on.
Requires an active paid subscription.
SMS credit packs
SMS credits are metered per message, so a pack is a one-off Stripe purchase rather than a
subscription line item — buy more whenever you run low. Available on Studio and Agency,
since sms is a Studio and Agency feature:
POST /v1/billing/addons/sms-credits{ "packs": 2 }Response:
{
"url": "https://checkout.stripe.com/c/pay/cs_live_...",
"packs": 2,
"credits": 100
}Each pack is 50 credits (1–20 packs per purchase). Redirect the user to url to complete
payment; credits are granted once Stripe confirms the payment via webhook, not from this
response. A plan without the sms feature gets plan_required; a deployment without SMS
sending configured (no Twilio credentials) refuses the purchase outright, since selling
credits it cannot deliver would be taking money for nothing.
Extra seats
Seats are bought with the plan — pass seats to POST /v1/billing/checkout, or change the
quantity later from the billing portal. A yearly plan bills seats yearly, because every
recurring item on one subscription has to share a billing interval.
A seat is a person who signs in to the dashboard. Clients never take one: they open their request through the link they were emailed and never get an account at all.
Buying a seat does not fill it — invite someone into it from Settings → Team, or:
POST /v1/team/invites
{ "email": "colleague@example.com" }They get an email with a one-time link, set their own password, and land in the same account
with the member role. Members can see and run intakes; only the owner can invite, remove
people, change billing or delete the account.
Pending invitations count against the seat quota, so a stack of unopened invitations cannot
reserve the same seat twice over. GET /v1/team returns the current roster and anything still
pending; GET /v1/usage reports seats.used against seats.limit.
Removing someone (Settings → Team, or DELETE /v1/team/members/:id) ends their sessions
immediately and frees the seat. The owner cannot be removed.
Upgrading
Start a checkout session via API:
POST /v1/billing/checkout{
"plan": "solo",
"interval": "monthly"
}Response:
{
"url": "https://checkout.stripe.com/c/pay/cs_live_..."
}Redirect the user (or open the URL in a browser) to complete payment via Stripe. After payment, the plan is active immediately and existing intakes are not affected.
For annual billing, set "interval": "yearly". Add "seats": 2 to include extra Agency seats in the same checkout (Studio is a single seat and does not accept this parameter).
The Stripe Checkout page accepts promotion codes. There is no API parameter for them — the person completing the checkout enters the code on the Stripe page.
Current public code: AGENT20 — 20% off subscription invoices for the first 3 months. On annual billing that means 20% off the first annual payment.
Managing your subscription
Open the Stripe Customer Portal to change plan, update payment method, or cancel:
POST /v1/billing/portalResponse:
{
"url": "https://billing.stripe.com/session/..."
}Portal sessions expire after 5 minutes. Generate a new one if the user does not use it in time.
EU/CZ consumers also have a statutory 14-day right of withdrawal, separate from this
cancellation flow — see docs/terms.md. It is handled by GET /v1/billing/withdrawal
(preview what a withdrawal right now would refund) and POST /v1/billing/withdraw
(record it and cancel the subscription); both are dashboard-session-only, owner or member.
Checking usage
Works with either a dashboard session or an API key — no extra scope required.
GET /v1/usageReturns current period usage against your plan limits:
{
"tier": "solo",
"active_intakes": { "used": 7, "limit": 15 },
"storage": { "used_bytes": 3221225472, "limit_bytes": 26843545600 },
"seats": { "used": 2, "limit": 2 },
"sms_credits": 0,
"subscription": { "active": true },
"rate_limit_per_hour": 600,
"features": {
"secrets_vault": true,
"revisions": true,
"sms": false,
"custom_branding": true,
"custom_domain": false,
"custom_templates": true
},
"chase_schedules": ["default", "gentle", "aggressive", "custom", "off"]
}active_intakes counts intakes in draft, sent, or in_progress status. Completed and archived intakes do not count toward the limit — and a draft counts, deliberately, so an intake being assembled across several tool calls still occupies its slot.
subscription.active tells you whether this is a real, paying Stripe subscription rather than a tier granted directly (comped, or set by an operator) — from the limits alone the two look identical. features mirrors the same feature flags as GET /pricing.json, but scoped to what this specific account can actually use right now.
chase_schedules is what chase_schedule on POST /v1/intakes and PATCH /v1/intakes/:id will actually accept right now — on the Free plan that is ["default", "off"]; see Chase engine.
Machine-readable pricing
Agents can fetch current pricing without scraping the landing page:
GET https://api.briefgate.dev/pricing.jsonNo authentication required. Returns the TIER_LIMITS object with all plan features and numeric limits. The response is cacheable for 5 minutes (Cache-Control: public, max-age=300) and CORS is open, so any origin can fetch it directly.
Data retention
- Default: data is retained 150 days after
intake.completed, then automatically purged (files + submitted values) - Configure retention per account:
PATCH /v1/account
{"retention_days": 365}Valid range: 1 to 3650 days.
- For immediate deletion of a specific intake (including all files in R2 storage):
DELETE /v1/intakes/:idThis is irreversible. The intake, all submitted values, all files, and all chase history are removed.
For full account deletion, contact support. All data is removed within 30 days.
If a payment fails
Nothing is deleted, and nothing is switched off immediately.
When Stripe reports a subscription as past_due or unpaid, the account keeps
its plan and every add-on for a 14-day grace period, so a card that expired
over a weekend does not cost anyone their work.
You will know about it: every owner on the account gets an e-mail the moment
the grace period starts, with the amount that failed, the date the grace period
ends and a one-click link to update the card in the Stripe customer portal. The
dashboard shows the same warning as a banner on every page until the payment
goes through, and a second e-mail confirms when it does. Stripe keeps retrying
the card on its own during those two weeks (Smart Retries) and sends its own
payment-failed notice as well. GET /v1/auth/me and GET /v1/account expose
the state as billing_grace_until (ISO date or null) and
billing_grace_expired, so an agent can surface it too.
If the grace period ends without the payment succeeding, free-tier limits start applying to new intakes only. Intakes that already exist keep running: clients can still submit, reminders still go out, and results stay retrievable. Paying restores the plan on the next Stripe event, with nothing to restore manually.
Data is only ever removed by the retention policy on an intake, by an explicit delete, or by account deletion — never by a failed payment.