Billing API

Billing is backed by Stripe. All routes are mounted under /v1/billing and require an authenticated session. Usage is metered per organization; payment methods, subscriptions, and invoices are managed through Stripe.

Get Billing Config

GET /v1/billing/config

Returns the public Stripe configuration the frontend needs (publishable key) and the enabled billing feature flags.

{
  "publishable_key": "pk_live_...",
  "features": { }
}

Get Billing Account

GET /v1/billing/account

Returns the billing account for the current user's organization.

Response:

{
  "id": 1,
  "organization_id": 1,
  "account_type": "organization",
  "currency": "usd",
  "billing_mode": "postpaid",
  "status": "active",
  "stripe_customer_id": "cus_...",
  "stripe_subscription_id": "sub_...",
  "subscription_status": "active",
  "collection_method": "charge_automatically",
  "current_period_start": "2025-06-01T00:00:00Z",
  "current_period_end": "2025-07-01T00:00:00Z",
  "auto_charge_enabled_at": "2025-06-01T00:00:00Z",
  "auto_charge_enabled_by_user_id": 42,
  "max_active_resources": 5,
  "created_at": "2025-01-15T09:00:00Z",
  "updated_at": "2025-06-17T10:00:00Z"
}

Get Usage Summary

GET /v1/billing/usage-summary

Returns metered usage totals for the current billing period.

Response:

{
  "organization_id": 1,
  "period_start": "2025-06-01T00:00:00Z",
  "period_end": "2025-07-01T00:00:00Z",
  "currency": "usd",
  "usage_totals": [
    {
      "meter": "gpu_instance_seconds",
      "unit": "second",
      "total_quantity": "171360",
      "service_key": "aws.gpu.ml.g5.xlarge",
      "display_name": "GPU instance (ml.g5.xlarge)",
      "dimensions": { "instance_type": "ml.g5.xlarge", "region": "us-east-1" },
      "unit_amount_decimal": "0.000280",
      "unit_amount_currency": "usd",
      "estimated_amount": "47.980800",
      "estimated_amount_currency": "usd"
    }
  ],
  "open_anomalies": 0
}

Get Subscription

GET /v1/billing/subscription

Response:

{
  "billing_account_id": 1,
  "subscription_status": "active",
  "collection_method": "charge_automatically",
  "current_period_start": "2025-06-01T00:00:00Z",
  "current_period_end": "2025-07-01T00:00:00Z"
}

Related subscription routes:

POST /v1/billing/subscription/activate-postpaid
PATCH /v1/billing/subscription/collection-method
  • POST .../subscription/activate-postpaid — activate postpaid billing using a Stripe payment method (stripe_payment_method_id).
  • PATCH .../subscription/collection-method — set collection_method to charge_automatically or send_invoice.

Payment Methods

GET /v1/billing/payment-methods
PATCH /v1/billing/payment-methods/default
DELETE /v1/billing/payment-methods/{payment_method_id}

GET returns a JSON array of saved cards:

[
  {
    "id": "pm_...",
    "brand": "visa",
    "last4": "4242",
    "exp_month": 12,
    "exp_year": 2027,
    "is_default": true,
    "allow_redisplay": "always"
  }
]
  • PATCH .../payment-methods/default — set the default payment method (stripe_default_payment_method_id).
  • DELETE .../payment-methods/{payment_method_id} — detach a card; responds 204 No Content.

Customer Portal & Checkout

POST /v1/billing/portal/session
POST /v1/billing/checkout/setup-session

POST .../portal/session creates a Stripe Customer Portal session and returns its URL:

{ "url": "https://billing.stripe.com/session/..." }

POST .../checkout/setup-session creates a Stripe Checkout session (request: optional return_url, purpose = payment_method_setup or postpaid_activation):

{
  "checkout_session_id": "cs_...",
  "client_secret": "cs_..._secret_...",
  "mode": "setup",
  "status": "open",
  "payment_status": "unpaid",
  "expires_at": "2025-06-17T11:00:00Z"
}

List Invoices

GET /v1/billing/invoices

Returns a JSON array of Stripe invoices:

[
  {
    "stripe_invoice_id": "in_...",
    "status": "paid",
    "collection_method": "charge_automatically",
    "amount_due": 4798,
    "amount_paid": 4798,
    "currency": "usd",
    "hosted_invoice_url": "https://invoice.stripe.com/i/...",
    "invoice_pdf": "https://pay.stripe.com/invoice/.../pdf",
    "due_date": null,
    "period_start": "2025-06-01T00:00:00Z",
    "period_end": "2025-07-01T00:00:00Z",
    "created": "2025-07-01T00:05:00Z"
  }
]

Amounts are in the currency's smallest unit (e.g. cents).


Stripe Webhook

POST /v1/billing/webhook

Receives Stripe webhook events (subscription and invoice lifecycle, payment updates). This endpoint is called by Stripe, not by API clients.