Billing & Subscriptions
Manage subscriptions, view invoices, and update payment methods. Billing is powered by Stripe and operates at the organization level.
Subscription Status
GET /v1/billing/subscription-status Get the current subscription status for the authenticated user’s organization. The organization is resolved from the authenticated session; no query parameters are required.
Response
{
"data": {
"status": "active",
"has_paid_subscription": true,
"plan_name": "Backbuild Pro",
"trial_end": null,
"credits_monthly": 0,
"current_period_start": "2026-04-01T00:00:00Z",
"current_period_end": "2026-05-01T00:00:00Z"
}
} List Subscriptions
GET /v1/billing/subscriptions The organization is resolved from the authenticated session.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: active, trialing, past_due, canceled, incomplete, paused |
limit | integer | Max results (default: 25, max: 100) |
offset | integer | Pagination offset |
Create Subscription
POST /v1/billing/subscriptions
Subscribe the authenticated user’s organization to a pricing plan using
a Stripe payment method that has already been collected. The organization is
resolved from the session. To collect payment via a hosted Stripe Checkout
page instead, use POST /v1/billing/create-checkout-session.
Request Body
{
"plan_id": "...",
"interval": "month",
"payment_method_id": "pm_...",
"billing_details": {
"name": "Acme Inc.",
"email": "billing@example.com"
},
"seats": 5
}
Do not send id, org_id, status,
created_at, or updated_at; these are assigned
by the server, and the organization is resolved from the authenticated session.
Response
On success the complete created subscription record is returned.
{
"success": true,
"data": {
"id": "...",
"stripe_subscription_id": "sub_...",
"plan_key": "...",
"status": "active",
"current_period_start": "2026-04-01T00:00:00Z",
"current_period_end": "2026-05-01T00:00:00Z",
"cancel_at": null,
"trial_end": null,
"quantity": 5,
"metadata": {},
"prerequisite_subscription_id": null,
"created_at": "2026-04-01T00:00:00Z",
"updated_at": "2026-04-01T00:00:00Z"
}
} Response Codes
| Status | Meaning |
|---|---|
201 Created | Subscription created; the full record is returned |
400 Bad Request | Request body validation failure (e.g. missing plan, invalid interval, or malformed payment details) |
401 Unauthorized | Missing or invalid access token |
500 Internal Server Error | Unexpected server error (including payment-provider failures and duplicate-subscription rejections) |
Hosted Checkout (redirect flow)
POST /v1/billing/create-checkout-session
Creates a Stripe Checkout session and returns its URL for redirect-based
payment collection. Request body: price_id, package_id,
and optional success_url, cancel_url, and
trial_period_days. The success_url and
cancel_url values are validated against an allowlist of permitted
application domains, preventing open redirect attacks through Stripe Checkout.
Update Subscription
PUT /v1/billing/subscriptions/:id Change the plan, adjust seats, or schedule cancellation for an existing subscription.
Request Body
{
"plan_id": "...",
"seats": 10,
"cancel_at_period_end": false
} List Invoices
GET /v1/billing/invoices The organization is resolved from the authenticated session.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: draft, open, paid, uncollectible, void |
limit | integer | Max results (default: 25, max: 100) |
offset | integer | Pagination offset |
Response
{
"success": true,
"data": {
"items": [
{
"id": "...",
"invoice_number": "...",
"status": "paid",
"amount_due": 9900,
"amount_paid": 9900,
"currency": "usd",
"due_date": "2026-03-01T00:00:00Z",
"paid_at": "2026-03-01T00:05:00Z",
"hosted_invoice_url": "https://invoice.stripe.com/...",
"pdf_url": "https://pay.stripe.com/..."
}
],
"total": 12,
"page": 1,
"page_size": 25
}
} Update Payment Method
PUT /v1/billing/payment-methods Attach (or update the default) Stripe payment method for the authenticated user’s organization. The payment method is verified to belong to the organization’s Stripe customer before it is recorded. The organization is resolved from the session.
Request Body
{
"payment_method_id": "pm_...",
"set_as_default": true,
"billing_details": {
"name": "Acme Inc.",
"email": "billing@example.com"
}
}