Skip to content

Billing

Start a subscription by creating a Stripe Checkout session.

POST /v1/billing/checkout

Auth: Required

Request body:

{
"tier": "pro"
}
FieldTypeRequiredDescription
tierstringYes"pro" ($29/mo)

Response:

{
"checkout_url": "https://checkout.stripe.com/c/pay/cs_test_..."
}

Redirect the user to checkout_url to complete payment. After checkout, a webhook updates the account’s plan_tier automatically.

If the account has no Stripe customer yet, one is created automatically.

Open the Stripe Customer Portal for self-service subscription management — update payment method, view invoices, or cancel.

POST /v1/billing/portal

Auth: Required

Response:

{
"portal_url": "https://billing.stripe.com/p/session/..."
}

Returns 400 if the account has no billing history (never subscribed).

Return the current plan and subscription status.

GET /v1/billing

Auth: Required

Response (subscribed):

{
"plan": "pro",
"status": "active",
"current_period_end": "2026-04-01T00:00:00Z",
"cancel_at_period_end": false
}

Response (free tier):

{
"plan": "free",
"status": null,
"current_period_end": null,
"cancel_at_period_end": null
}
FieldTypeDescription
planstringCurrent tier: free, pro, or enterprise
statusstring | nullSubscription status: active, past_due, canceled, etc.
current_period_endstring | nullISO 8601 timestamp when the current billing period ends
cancel_at_period_endboolean | nullWhether the subscription will cancel at period end
POST /v1/billing/webhooks

Auth: None (verified via Stripe-Signature header)

This endpoint receives Stripe webhook events. Do not call it directly. It handles:

EventAction
checkout.session.completedActivates subscription, sets plan_tier
customer.subscription.updatedSyncs status, period, and tier changes
customer.subscription.deletedCancels subscription, downgrades to free
invoice.payment_failedMarks subscription as past_due

All events are processed idempotently — duplicate deliveries are safely ignored.