D driftstack docs

Billing

All Driftstack billing is a thin layer over Stripe. The Driftstack API mints checkout sessions + portal URLs; the customer interacts with the Stripe-hosted UI directly. Driftstack receives webhook events from Stripe (invoice.paid, customer.subscription.updated, etc.) and reflects them into the account’s subscription row + audit-log + email notifications.

Read billing state

GET /v1/billing

const state = await client.billing.getState();

Returns:

{
  "subscription": {
    "id": "sub_<uuid>",
    "tier": "api_builder",
    "status": "active",
    "billing_period": "monthly",
    "current_period_start": "2026-05-01T00:00:00Z",
    "current_period_end": "2026-06-01T00:00:00Z",
    "cancel_at_period_end": false
  },
  "trial_pack": {
    "active": false,
    "credit_cents_remaining": 0,
    "expires_at": null,
    "redeemed": false
  }
}

subscription is null when the account has never subscribed. trial_pack.active is true while the customer has unspent credit and the 14-day window hasn’t elapsed.

Start a subscription

POST /v1/billing/checkout-session

{
  "tier": "api_builder",
  "billing_period": "monthly",
  "success_url": "https://your.app/billing/success?session_id={CHECKOUT_SESSION_ID}",
  "cancel_url": "https://your.app/billing/cancel"
}

Returns { checkout_url, checkout_session_id }. Redirect the customer to checkout_url; Stripe handles card collection + 3DS + tax compliance and posts the result back to your success_url.

success_url and cancel_url are validated against an allowlist (V-248). Customers self-hosting Driftstack configure the allowlist in their deployment env.

Start the trial pack

POST /v1/billing/trial-pack

{
  "success_url": "https://your.app/billing/success",
  "cancel_url": "https://your.app/billing/cancel"
}

Returns the same { checkout_url, checkout_session_id } shape. The trial pack is a one-time $2.99 charge that credits 299¢ of session-time at the API Starter overage rate ($0.18 / concurrent- hour); ~16 hours of use. Once-per-account.

Open the Stripe Customer Portal

POST /v1/billing/portal-session

const { portal_url } = await client.billing.startPortalSession();

Returns a short-lived one-time URL into Stripe’s hosted Customer Portal. The customer manages their payment method, downloads invoices, cancels, or upgrades / downgrades from the portal. Driftstack receives the resulting Stripe events via webhook + the account’s subscription row updates.

The portal URL is single-use and short-lived. Mint a fresh one each time the customer clicks “Manage subscription” — don’t cache.

Webhook events from Stripe → Driftstack → Customer

When Stripe fires customer.subscription.updated (or any of the ~10 lifecycle events Driftstack subscribes to), Driftstack records the change in the account’s audit log (subscription.tier_changed with payload.from + payload.to) and optionally fires a customer-facing webhook event.

See Webhook events catalog for the planned subscription.changed / subscription.cancelled events; today the subscription.tier_changed audit row is the source of truth for programmatic consumers.

Auth + scoping

All /v1/billing/* endpoints are bearer-authenticated and scoped to the calling account. They do NOT honor the team-RBAC X-Driftstack-Account header — billing is always per-account, not per-team-context. Team owners manage their own billing; team members never see the owner’s billing state.