Billing and capacity
The API sponsor pays for production capacity in bands of connections. Partner invitations, workloads, replicas and certificate rotations are included.
What is a connection?
A production connection is one distinct (production service, consuming organization) pair with at least one active or suspended grant.
| Situation | Connections |
|---|---|
| Several workloads, replicas, certificate renewals or re-enrollments for the same service and partner | 1 |
| The same partner on a second production service | +1 |
| A second partner on the same service | +1 |
| Your own organization as the consumer of your own service | 1 (counts like any partner) |
| Suspended grant | Keeps its slot, shown as reserved |
| Sandbox grants, pending invitations, withdrawn or expired grants | 0 |
The limit is enforced atomically when a grant activates: accepting an invitation that would create a new pair beyond your capacity fails with 409 capacity_exceeded. Adding workloads to an existing pair never does.
Plans
| SKU | Plan | Capacity | Price |
|---|---|---|---|
team_10 | Team · 10 connections | 10 | USD 299 / month |
team_50 | Team · 50 connections | 50 | USD 799 / month |
| None | Enterprise and channel | Contracted | Annual contract or invoice terms through your Sectigo account team |
The sandbox is free, needs no card, and consumes nothing. Invited partner admins participate in a paying sponsor’s relationship without buying a plan.
Buy with Stripe Checkout
Requires the billing_admin role in the organization. An owner must be explicitly assigned it (see Organization). The server maps the SKU to a Stripe price, binds your Stripe customer and fixes the redirect URLs; the client never sends a price.
POST https://app.mutualtrust.io/v1/billing/checkout-sessions
Idempotency-Key: 5c0e-checkout-team10
X-CSRF-Token: <csrf_token>
Content-Type: application/json
{ "org_id": "org_01jcqa7m2k9x4v8r3t6p5w2h7n", "sku": "team_10" }{
"operation_id": "chk_01jcqe6j8k0m2n4p6q8r0s2t4v",
"url": "https://checkout.stripe.com/c/pay/cs_live_…",
"mode": "live"
}Redirect the user to url. Card details stay with Stripe. Stripe returns to https://app.mutualtrust.io/#/billing?org=…&checkout=chk_…, where the portal shows pending until a verified Stripe event establishes the subscription. Entitlement is never inferred from the browser redirect.
| Status | Code | Meaning |
|---|---|---|
| 403 | forbidden | You lack billing_admin for this organization. |
| 409 | subscription_exists | The organization already has an active or in-grace subscription. Change capacity in the billing portal. |
| 409 | stripe_error | Stripe rejected the request; the message is Stripe’s. |
| 503 | billing_unconfigured / plan_unavailable | That plan is not offered on this deployment. Contact your Sectigo account team for contracted plans. |
| 503 | stripe_unavailable | Stripe is unavailable; retry shortly. |
Subscription and entitlement states
Mutual Trust keeps the Stripe subscription status and its own entitlement state separately:
| Stripe status | Entitlement | Effect |
|---|---|---|
active, trialing | active | New connections allowed up to capacity. |
past_due, unpaid | grace for 14 days, then blocked | During grace existing connections continue, but no new connection can be added. Owners and billing admins see a past-due notice with the grace end date. |
incomplete, paused, other | blocked | New grants are blocked. Revocation, evidence and export remain available. |
canceled, incomplete_expired | ended | No capacity. |
Grace advances with time even without a new Stripe event. Expiry, deliberate offboarding and emergency security actions are independent of billing.
Manage billing in the Stripe portal
POST https://app.mutualtrust.io/v1/billing/portal-sessions
X-CSRF-Token: <csrf_token>
Content-Type: application/json
{ "org_id": "org_01jcqa7m2k9x4v8r3t6p5w2h7n" }{
"url": "https://billing.stripe.com/p/session/live_…"
}Use the hosted portal to update a payment method, download invoices and change or cancel your plan. A billing admin can do this without any access to trust configuration.
Billing summary
GET /v1/organizations/{id}/billing (roles billing_admin, owner or auditor):
{
"configured": true,
"mode": "live",
"subscription": {
"id": "sub_01jcqe7k9m1n3p5q7r9s1t3v5w",
"stripe_status": "active",
"entitlement_state": "active",
"connections": 10,
"current_period_end": "2026-12-14T15:52:00Z",
"grace_ends_at": null,
"cancel_at": null,
"currency": "usd",
"plan_name": "Team · 10 connections",
"unit_amount": 29900,
"interval": "month"
},
"usage": {
"active": 3,
"reserved": 1,
"used": 4,
"capacity": 10,
"remaining": 6
},
"invoices": [
{
"number": "MT-0001",
"status": "paid",
"currency": "usd",
"total": 29900,
"amount_remaining": 0,
"due_at": "2026-11-14T15:52:00Z",
"paid_at": "2026-11-14T15:52:09Z",
"hosted_invoice_url": "https://invoice.stripe.com/i/…",
"issued_at": "2026-11-14T15:52:00Z"
}
],
"plans": [
{
"sku": "team_10",
"name": "Team · 10 connections",
"connections": 10,
"unit_amount": 29900,
"currency": "usd",
"interval": "month"
},
{
"sku": "team_50",
"name": "Team · 50 connections",
"connections": 50,
"unit_amount": 79900,
"currency": "usd",
"interval": "month"
}
],
"grace_days": 14
}Amounts are integer minor units with a lowercase ISO 4217 currency.
How payments are processed
- Stripe sends events to
POST https://api.mutualtrust.io/webhooks/stripe. The signature is verified on the raw body (5-minute tolerance) before parsing; events are stored in a de-duplicating inbox and acknowledged quickly. - A worker re-reads the current Stripe subscription, invoice or balance objects and applies idempotent transitions, so duplicated, delayed or reordered deliveries are safe.
- Every 6 hours a reconciler re-reads all known subscriptions and imports balance transactions and payouts, covering lost webhooks.