Billing Endpoints
Subscription management, usage tracking, and white-label billing for tenants.
Overview
Backflow has two billing systems:
- Platform Billing - Backflow charges tenants based on usage (API calls, storage, AI tokens)
- Tenant Billing - Tenants can bill their own customers using their own payment provider
Platform Billing
Get Plans
GET /billing/plans
List all available subscription plans with limits.
curl http://localhost:3000/billing/plans \
-H "Authorization: Bearer <token>"Response:
{
"plans": [
{
"tier": "free",
"name": "Free",
"description": "For individual developers",
"price": { "monthly": 0, "yearly": 0, "currency": "USD" },
"limits": {
"websocket": { "maxConnections": 10, "maxEntitiesWatched": 2 },
"fileStorage": { "maxStorageMB": 200, "maxFileSizeMB": 5 },
"api": { "requestsPerMinute": 100 },
"ai": { "llmTokensPerMonth": 100000, "maxCostPerMonth": 5 }
}
},
{
"tier": "pro",
"name": "Pro",
"description": "For small teams",
"price": { "monthly": 29, "yearly": 290, "currency": "USD" },
"limits": { ... }
}
]
}Get Subscription
GET /billing/subscription
Get current tenant subscription status.
curl http://localhost:3000/billing/subscription \
-H "Authorization: Bearer <token>"Response:
{
"tenantId": "tenant-123",
"subscription": {
"plan": "pro",
"status": "active",
"startDate": "2024-01-01T00:00:00Z",
"renewalDate": "2024-02-01T00:00:00Z",
"currentPeriodEnd": "2024-02-01T00:00:00Z",
"cancelAtPeriodEnd": false,
"paymentMethod": "card"
}
}Get Usage
GET /billing/usage
Get current resource usage against plan limits.
curl http://localhost:3000/billing/usage \
-H "Authorization: Bearer <token>"Response:
{
"tenantId": "tenant-123",
"plan": "pro",
"usage": {
"websocket": {
"connections": { "current": 45, "limit": 100, "percentage": 45 },
"entitiesWatched": { "current": 8, "limit": 10, "percentage": 80 },
"rooms": { "current": 3, "limit": 10, "percentage": 30 }
},
"fileStorage": {
"storage": {
"current": 1073741824,
"limit": 5368709120,
"percentage": 20,
"currentFormatted": "1 GB",
"limitFormatted": "5 GB"
}
},
"tenantConfig": {
"secrets": { "current": 12, "limit": 50, "percentage": 24 }
}
}
}Upgrade Plan
POST /billing/upgrade
Request upgrade to a higher plan. Returns a checkout URL.
curl -X POST http://localhost:3000/billing/upgrade \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"targetPlan": "pro",
"billingCycle": "monthly"
}'Response:
{
"success": true,
"checkoutUrl": "https://checkout.polar.sh/...",
"session": {
"id": "checkout-123",
"provider": "polar",
"plan": "pro",
"billing_cycle": "monthly",
"amount": 2900,
"currency": "USD"
}
}Sync Subscription
POST /billing/subscription/sync
Manually sync subscription status from payment provider.
curl -X POST http://localhost:3000/billing/subscription/sync \
-H "Authorization: Bearer <token>"Response:
{
"success": true,
"subscription": {
"plan": "pro",
"status": "active"
}
}Webhooks
Polar Webhook
POST /billing/webhook/polar
Receives webhook events from Polar for subscription lifecycle.
Configure in Polar Dashboard:
- Endpoint:
https://api.backflow.dev/billing/webhook/polar - Events:
subscription.created,subscription.updated,subscription.canceled,order.paid
The webhook validates signatures using POLAR_WEBHOOK_SECRET.
Stripe Webhook
POST /webhooks/billing/stripe
Receives webhook events from Stripe (if configured).
Configure in Stripe Dashboard:
- Endpoint:
https://api.backflow.dev/webhooks/billing/stripe - Events:
checkout.session.completed,customer.subscription.*,invoice.*
Tenant Billing (White-Label)
Tenants can use their own payment provider to bill their customers. This requires storing payment provider credentials in tenant secrets.
Setup
- Store your Polar API key in secrets:
curl -X POST http://localhost:3000/tenant/secrets \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"key": "polar_api_key",
"value": "polar_sk_live_..."
}'- Optionally store organization ID:
curl -X POST http://localhost:3000/tenant/secrets \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"key": "polar_organization_id",
"value": "org-123"
}'List Products
GET /billing/tenant/products
List products from your Polar organization.
curl http://localhost:3000/billing/tenant/products \
-H "Authorization: Bearer <token>"Response:
{
"items": [
{
"id": "prod-123",
"name": "Pro Plan",
"description": "Access to all features",
"prices": [
{ "id": "price-123", "amount": 2900, "currency": "usd", "interval": "month" }
]
}
]
}Create Product
POST /billing/tenant/products
Create a product in your Polar organization.
curl -X POST http://localhost:3000/billing/tenant/products \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Enterprise Plan",
"description": "For large teams",
"prices": [
{ "amount": 9900, "currency": "usd", "interval": "month" }
]
}'Create Checkout
POST /billing/tenant/checkout
Create a checkout session for your customer.
curl -X POST http://localhost:3000/billing/tenant/checkout \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"productPriceId": "price-123",
"customerEmail": "customer@example.com",
"successUrl": "https://yourapp.com/success",
"cancelUrl": "https://yourapp.com/cancel"
}'Response:
{
"id": "checkout-456",
"url": "https://checkout.polar.sh/..."
}List Customers
GET /billing/tenant/customers
List customers from your Polar organization.
curl http://localhost:3000/billing/tenant/customers \
-H "Authorization: Bearer <token>"Response:
{
"items": [
{
"id": "cust-123",
"email": "customer@example.com",
"name": "John Doe",
"created_at": "2024-01-15T00:00:00Z"
}
]
}List Subscriptions
GET /billing/tenant/subscriptions
List subscriptions from your Polar organization.
curl http://localhost:3000/billing/tenant/subscriptions \
-H "Authorization: Bearer <token>"Response:
{
"items": [
{
"id": "sub-123",
"customer_id": "cust-123",
"status": "active",
"current_period_end": "2024-02-15T00:00:00Z",
"product": { "name": "Pro Plan" }
}
]
}Cancel Subscription
DELETE /billing/tenant/subscriptions/:id
Cancel a customer's subscription.
curl -X DELETE http://localhost:3000/billing/tenant/subscriptions/sub-123 \
-H "Authorization: Bearer <token>"Get Customer State
GET /billing/tenant/customers/:id/state
Get subscription state for a specific customer.
curl http://localhost:3000/billing/tenant/customers/cust-123/state \
-H "Authorization: Bearer <token>"Response:
{
"customerId": "cust-123",
"hasActiveSubscription": true,
"subscriptions": [
{
"id": "sub-123",
"status": "active",
"product": "Pro Plan"
}
]
}Plan Tiers
| Tier | Monthly | WebSocket Connections | Storage | API Rate | AI Tokens/Month |
|---|---|---|---|---|---|
| Free | $0 | 10 | 200 MB | 100/min | 100K |
| Pro | $29 | 100 | 5 GB | 1,000/min | 10M |
| Team | $99 | 500 | 25 GB | 3,000/min | 50M |
| Scale | $299 | 2,000 | 100 GB | 6,000/min | 75M |
| Enterprise | Custom | 10,000+ | Unlimited | 10,000/min | Unlimited |
Tier Enforcement
Usage is tracked in real-time and enforced before operations. When limits are exceeded:
{
"error": "Usage limit exceeded",
"message": "WebSocket connection limit reached (10)",
"allowed": false,
"upgrade": {
"plan": "pro",
"limit": 100
}
}Status: 402 Payment Required
Environment Variables
# Payment Provider
PAYMENT_PROVIDER=polar
# Polar Configuration
POLAR_API_KEY=polar_sk_...
POLAR_ORGANIZATION_ID=org-123
POLAR_WEBHOOK_SECRET=polar_whs_...
# Product Mappings (reverse mapping product->tier is derived automatically)
POLAR_PRODUCT_MAP={"pro_monthly":"price-123","pro_yearly":"price-456",...}
# App URL (for checkout redirects)
APP_URL=https://app.backflow.dev