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
json
{ "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
json
{ "packs": 2 }

Response:

json
{
  "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
json
{
  "plan": "solo",
  "interval": "monthly"
}

Response:

json
{
  "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/portal

Response:

json
{
  "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/usage

Returns current period usage against your plan limits:

json
{
  "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.json

No 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

PATCH /v1/account
{"retention_days": 365}

Valid range: 1 to 3650 days.

DELETE /v1/intakes/:id

This 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.