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

ParameterTypeDescription
statusstringFilter: active, trialing, past_due, canceled, incomplete, paused
limitintegerMax results (default: 25, max: 100)
offsetintegerPagination 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

StatusMeaning
201 CreatedSubscription created; the full record is returned
400 Bad RequestRequest body validation failure (e.g. missing plan, invalid interval, or malformed payment details)
401 UnauthorizedMissing or invalid access token
500 Internal Server ErrorUnexpected 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

ParameterTypeDescription
statusstringFilter: draft, open, paid, uncollectible, void
limitintegerMax results (default: 25, max: 100)
offsetintegerPagination 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"
  }
}