{"openapi":"3.1.0","info":{"title":"LedgerBill API","version":"1.0.0","description":"Customer-facing LedgerBill API for tenant authentication, subscriptions, API keys, customer records, usage reporting, and provider webhooks. Platform Admin, LedgerBill team, dashboard operations, diagnostics, route governance, and key-rotation APIs are intentionally excluded.","x-governance":{"retentionPolicyRef":"policy://ledgerbill/records-retention/v1","terms":["retention period","archival","disposition","legal hold"]}},"servers":[{"url":"https://ledgerbill.app","description":"Current environment"}],"tags":[{"name":"Auth","description":"Authentication and identity endpoints"},{"name":"Tenants","description":"Tenant management endpoints"},{"name":"Runtime","description":"Customer and usage runtime APIs"},{"name":"Subscriptions","description":"Checkout and subscription views"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT bearer token from Auth0 or the LedgerBill session issuer"},"CookieAuth":{"type":"apiKey","in":"cookie","name":"auth_token","description":"Session cookie set after the Auth0 callback flow completes"},"TenantApiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"Tenant-scoped API key for programmatic access"},"TenantHeader":{"type":"apiKey","in":"header","name":"x-tenant-id","description":"Tenant context required for user-session scoped calls"}},"headers":{"RateLimitLimit":{"description":"Rate limit quota for the current policy window","schema":{"type":"integer"}},"RateLimitRemaining":{"description":"Remaining requests in current rate limit window","schema":{"type":"integer"}},"RateLimitReset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer"}},"IdempotencyReplayed":{"description":"True when a response is replayed from an existing idempotency record","schema":{"type":"string","enum":["true"]}}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":255},"description":"IETF idempotency key for safe retries on POST requests."}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"]},"CreateCustomerRequest":{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"},"externalId":{"type":"string"}},"required":["email","name"]},"ReportUsageRequest":{"type":"object","properties":{"customerId":{"type":"string"},"featureKey":{"type":"string"},"amount":{"type":"number"},"timestamp":{"type":"string","format":"date-time"}},"required":["customerId","featureKey","amount"]},"UsageRatingDecision":{"type":"object","properties":{"ratingVersion":{"type":"string","example":"rating.v1.events"},"planId":{"type":"string","nullable":true},"featureKey":{"type":"string"},"periodStart":{"type":"string","format":"date-time"},"periodEnd":{"type":"string","format":"date-time"},"usageReported":{"type":"integer"},"consumedBefore":{"type":"integer"},"consumedAfter":{"type":"integer"},"includedUnits":{"type":"integer","nullable":true},"billableOverageUnits":{"type":"integer"},"estimatedChargeMinor":{"type":"integer"},"currency":{"type":"string","example":"usd"},"rated":{"type":"boolean"},"reason":{"type":"string","nullable":true}},"required":["ratingVersion","planId","featureKey","periodStart","periodEnd","usageReported","consumedBefore","consumedAfter","includedUnits","billableOverageUnits","estimatedChargeMinor","currency","rated"]},"UsageAcceptedResponse":{"type":"object","properties":{"status":{"type":"string","enum":["accepted"]},"tenantId":{"type":"string"},"customerId":{"type":"string"},"rating":{"$ref":"#/components/schemas/UsageRatingDecision"}},"required":["status","tenantId","customerId","rating"]},"UsagePreviewResponse":{"type":"object","properties":{"status":{"type":"string","enum":["preview"]},"tenantId":{"type":"string"},"customerId":{"type":"string"},"rating":{"$ref":"#/components/schemas/UsageRatingDecision"}},"required":["status","tenantId","customerId","rating"]},"CheckoutRequest":{"type":"object","properties":{"planId":{"type":"string","example":"professional"}},"required":["planId"]},"PricingPlan":{"type":"object","properties":{"planId":{"type":"string","example":"professional"},"tier":{"type":"string","example":"Professional"},"description":{"type":"string"},"priceLabel":{"type":"string","example":"$199"},"amountMinor":{"type":"integer","nullable":true,"example":19900},"currency":{"type":"string","example":"usd"},"interval":{"type":"string","enum":["month","year","custom"]},"includedEventsMonthly":{"type":"integer","nullable":true,"example":100000},"overagePer100kMinor":{"type":"integer","nullable":true,"example":900},"features":{"type":"array","items":{"type":"string"}},"highlighted":{"type":"boolean"},"active":{"type":"boolean"},"contactSales":{"type":"boolean"},"stripeProductId":{"type":"string","nullable":true},"checkoutEnabled":{"type":"boolean"}},"required":["planId","tier","description","priceLabel","currency","interval","features","highlighted","active","contactSales","checkoutEnabled"]},"PricingCatalogResponse":{"type":"object","properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/PricingPlan"}},"checkoutEligiblePlanIds":{"type":"array","items":{"type":"string"}},"billingSetup":{"type":"object","properties":{"ready":{"type":"boolean"},"missingCheckoutPlanIds":{"type":"array","items":{"type":"string"}},"notes":{"type":"array","items":{"type":"string"}}},"required":["ready","missingCheckoutPlanIds","notes"]},"currency":{"type":"string"},"source":{"type":"string"}},"required":["plans","checkoutEligiblePlanIds","billingSetup"]},"CheckoutResponse":{"type":"object","properties":{"url":{"type":"string","nullable":true},"sessionId":{"type":"string"},"plan":{"$ref":"#/components/schemas/PricingPlan"}},"required":["url","sessionId","plan"]},"CurrentSubscriptionResponse":{"type":"object","properties":{"id":{"type":"string"},"tenant_id":{"type":"string"},"stripe_customer_id":{"type":"string","nullable":true},"stripe_subscription_id":{"type":"string","nullable":true},"plan_id":{"type":"string","nullable":true},"status":{"type":"string"},"plan":{"oneOf":[{"$ref":"#/components/schemas/PricingPlan"},{"type":"null"}]}},"required":["status","plan"]},"TenantCreateRequest":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]},"ApiKeyCreateRequest":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}}},"paths":{"/api/auth/register":{"post":{"tags":["Auth"],"summary":"Request access through Auth0 Universal Login","responses":{"400":{"description":"Auth0 Universal Login required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/login":{"post":{"tags":["Auth"],"summary":"Request login through Auth0 Universal Login","responses":{"400":{"description":"Auth0 Universal Login required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/logout":{"post":{"tags":["Auth"],"summary":"Logout user","responses":{"200":{"description":"Logged out"}}}},"/api/auth/me":{"get":{"tags":["Auth"],"summary":"Get current authenticated user","security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"User details"},"401":{"description":"Authentication required"}}}},"/api/auth/verify-email":{"post":{"tags":["Auth"],"summary":"Mark authenticated user email as verified","security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Email verification updated"},"401":{"description":"Authentication required"}}}},"/api/tenants":{"post":{"tags":["Tenants"],"summary":"Create tenant","security":[{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantCreateRequest"}}}},"responses":{"201":{"description":"Tenant created"}}}},"/api/tenants/{id}":{"get":{"tags":["Tenants"],"summary":"Get tenant by id","security":[{"CookieAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tenant details"},"403":{"description":"Access denied"},"404":{"description":"Not found"}}}},"/api/subscriptions/checkout":{"post":{"tags":["Subscriptions"],"summary":"Create Stripe checkout session (alias)","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"200":{"description":"Checkout session url","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}},"headers":{"IdempotencyReplayed":{"$ref":"#/components/headers/IdempotencyReplayed"}}},"429":{"description":"Rate limited","headers":{"RateLimitLimit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimitRemaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimitReset":{"$ref":"#/components/headers/RateLimitReset"}}}}}},"/api/pricing/plans":{"get":{"tags":["Subscriptions"],"summary":"Get public pricing plan catalog","responses":{"200":{"description":"Active pricing plans and checkout eligibility","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingCatalogResponse"}}}}}}},"/api/subscriptions/plans":{"get":{"tags":["Subscriptions"],"summary":"Get tenant-scoped subscription plan catalog","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"responses":{"200":{"description":"Plan catalog for authenticated tenant context","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PricingCatalogResponse"},{"type":"object","properties":{"tenantId":{"type":"string"}},"required":["tenantId"]}]}}}}}}},"/api/subscriptions/current":{"get":{"tags":["Subscriptions"],"summary":"Get current tenant subscription projection","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"responses":{"200":{"description":"Subscription state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentSubscriptionResponse"}}}}}}},"/api/subscriptions/portal":{"post":{"tags":["Subscriptions"],"summary":"Create Stripe customer portal session","description":"Creates a self-service billing portal session for the tenant's Stripe customer record.","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"responses":{"200":{"description":"Billing portal URL","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]}}}},"400":{"description":"No Stripe customer mapped for tenant"}}}},"/api/billing/entitlements":{"get":{"tags":["Subscriptions"],"summary":"Get proof entitlements for authenticated user","security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Proof entitlement state"},"401":{"description":"Authentication required"}}}},"/api/proof/access":{"get":{"tags":["Subscriptions"],"summary":"Get proof access response for authenticated user","security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Proof access payload"},"401":{"description":"Authentication required"},"403":{"description":"Proof access required"}}}},"/api/v1/customers":{"post":{"tags":["Runtime"],"summary":"Create customer in canonical ledger","x-retention-policy-ref":"policy://ledgerbill/records-retention/v1#customer-events","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerRequest"}}}},"responses":{"201":{"description":"Customer created","headers":{"IdempotencyReplayed":{"$ref":"#/components/headers/IdempotencyReplayed"}}},"429":{"description":"Rate limited","headers":{"RateLimitLimit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimitRemaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimitReset":{"$ref":"#/components/headers/RateLimitReset"}}}}}},"/api/v1/usage":{"post":{"tags":["Runtime"],"summary":"Report usage and return explicit rating decision","x-retention-policy-ref":"policy://ledgerbill/records-retention/v1#usage-events","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportUsageRequest"}}}},"responses":{"200":{"description":"Accepted with rating decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageAcceptedResponse"}}},"headers":{"IdempotencyReplayed":{"$ref":"#/components/headers/IdempotencyReplayed"}}},"429":{"description":"Rate limited","headers":{"RateLimitLimit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimitRemaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimitReset":{"$ref":"#/components/headers/RateLimitReset"}}}}}},"/api/v1/usage/preview":{"post":{"tags":["Runtime"],"summary":"Preview usage rating decision without writing canonical events","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportUsageRequest"}}}},"responses":{"200":{"description":"Preview rating decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsagePreviewResponse"}}}}}}},"/api/webhooks/stripe":{"post":{"tags":["Runtime"],"summary":"Ingest platform Stripe webhook event","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Duplicate ignored"},"202":{"description":"Accepted"},"400":{"description":"Invalid payload, signature, or tenant ownership resolution failure"},"500":{"description":"Ingestion failure"}}}},"/api/webhooks/paypal":{"post":{"tags":["Runtime"],"summary":"Ingest PayPal webhook event (alias path)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"202":{"description":"Accepted"},"400":{"description":"Invalid payload/signature"},"500":{"description":"Ingestion failure"}}}},"/api/api-keys":{"post":{"tags":["Tenants"],"summary":"Create tenant API key","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateRequest"}}}},"responses":{"201":{"description":"API key created"}}},"get":{"tags":["Tenants"],"summary":"List tenant API keys","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"responses":{"200":{"description":"List API keys"}}}},"/api/api-keys/{id}":{"delete":{"tags":["Tenants"],"summary":"Revoke tenant API key","security":[{"TenantApiKey":[]},{"CookieAuth":[],"TenantHeader":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"API key revoked"},"404":{"description":"API key not found"}}}}}}