From f3370dab0a172fbdee2a3bd609d7bdcdf5c7d5c6 Mon Sep 17 00:00:00 2001 From: AEGIS Date: Sat, 4 Apr 2026 17:08:18 -0500 Subject: [PATCH] docs: add API key, billing guides and update getting-started for OAuth signup Add API key management guide covering generation, validation, rotation, and revocation (closes #8). Add billing & subscription docs covering Stripe checkout, customer portal, tier management, and webhook lifecycle (closes #9). Update getting-started to document OAuth signup flow and remove waitlist references (closes #10). Confirm pricing reflects $29/mo Pro tier across all pages (closes #7). Add cross-links from platform and ecosystem pages to the new guides. Closes #7, #8, #9, #10 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/content/docs/api-keys.md | 219 ++++++++++++++++++++++++ src/content/docs/billing.md | 254 ++++++++++++++++++++++++++++ src/content/docs/ecosystem.md | 4 +- src/content/docs/getting-started.md | 51 +++++- src/content/docs/platform.md | 2 + 5 files changed, 526 insertions(+), 4 deletions(-) create mode 100644 src/content/docs/api-keys.md create mode 100644 src/content/docs/billing.md diff --git a/src/content/docs/api-keys.md b/src/content/docs/api-keys.md new file mode 100644 index 0000000..94285dc --- /dev/null +++ b/src/content/docs/api-keys.md @@ -0,0 +1,219 @@ +--- +title: "API Key Management" +description: "Generate, validate, rotate, and revoke API keys for programmatic access to Stackbilt services." +section: "platform" +order: 10 +color: "#f59e0b" +tag: "10" +--- + +# API Key Management + +API keys provide programmatic access to Stackbilt services without requiring an interactive OAuth session. Use them for CI/CD pipelines, backend integrations, MCP clients, and automated workflows. + +## Key Prefixes + +Stackbilt uses prefixed keys to identify the key type and scope: + +| Prefix | Service | Description | +|--------|---------|-------------| +| `ea_` | edge-auth | General-purpose API keys issued through edge-auth | +| `sb_live_` | Stackbilder | Production keys for the Stackbilder platform | +| `sb_test_` | Stackbilder | Test/sandbox keys for development | +| `imgf_` | img-forge | Image generation API keys | + +All key types are validated through edge-auth's centralized identity layer. + +## Generating a Key + +### Via the REST API + +``` +POST https://auth.stackbilt.dev/api-keys +``` + +Requires an authenticated session. The response includes the raw key **once** -- store it securely, as it cannot be retrieved again. + +**Request body:** + +```json +{ + "orgId": "org_stackbilt", + "projectId": "prop_stackbilder", + "label": "CI/CD Pipeline", + "scopes": ["ai:invoke", "read"] +} +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `orgId` | string | Yes | Organization the key belongs to | +| `projectId` | string | No | Scope to a specific project (recommended) | +| `tenantId` | string | No | Scope to a specific tenant | +| `label` | string | No | Human-readable name for the key | +| `scopes` | string[] | No | Permission scopes (default: all scopes) | + +**Response (`201 Created`):** + +```json +{ + "key": "ea_abc123...xyz", + "keyId": "uuid", + "prefix": "ea_abc123" +} +``` + +### Via RPC (Service Binding) + +Other Stackbilt services call the `generateApiKey` RPC method on the `EdgeAuthEntrypoint`: + +```typescript +const result = await env.AUTH_SERVICE.generateApiKey({ + userId: "user-id", + name: "MCP Access Key", +}); +// result.key — raw key (store securely) +// result.id — key ID for management operations +``` + +## Using a Key + +Include the key in the `Authorization` header: + +```bash +curl -X GET https://auth.stackbilt.dev/api-keys?org_id=org_stackbilt \ + -H "Authorization: Bearer ea_your_key_here" +``` + +For img-forge, the `X-API-Key` header is also accepted: + +```bash +curl -X POST https://imgforge.stackbilt.dev/v2/generate \ + -H "X-API-Key: imgf_your_key_here" \ + -H "Content-Type: application/json" \ + -d '{"prompt": "A mountain landscape"}' +``` + +## Validation + +API key validation is constant-time and uses SHA-256 hashing. The system: + +1. Extracts the key prefix (first 11 characters) +2. Looks up the key row by prefix +3. Performs constant-time hash verification via Web Crypto +4. Checks expiration and revocation status +5. Returns the key's scopes, org, project, and tenant bindings + +**Validation response shape:** + +```json +{ + "valid": true, + "keyId": "uuid", + "userId": "user-id or null", + "orgId": "org_stackbilt", + "projectId": "prop_stackbilder or null", + "tenantId": "tenant-id or null", + "scopes": ["ai:invoke", "read"], + "rateLimit": { + "limit": 1000, + "remaining": 998, + "resetAt": 1234567890 + } +} +``` + +Invalid, revoked, or expired keys receive a uniform 403 denial with no distinguishing information. This prevents key enumeration and timing attacks. + +## Listing Keys + +``` +GET https://auth.stackbilt.dev/api-keys?org_id=org_stackbilt +``` + +Returns all active (non-revoked) keys for the organization. Raw key values are never returned -- only the prefix is shown. + +**Response:** + +```json +[ + { + "id": "uuid", + "prefix": "ea_abc1234", + "label": "CI/CD Pipeline", + "scopes": ["ai:invoke", "read"], + "projectId": "prop_stackbilder", + "lastUsedAt": "2026-04-01T12:00:00Z", + "createdAt": "2026-03-15T09:00:00Z" + } +] +``` + +## Revoking a Key + +``` +DELETE https://auth.stackbilt.dev/api-keys/:keyId +``` + +Revocation is a soft delete -- the key row is marked `revoked = 1` and immediately stops validating. Revoked keys cannot be un-revoked; generate a new key instead. + +```bash +curl -X DELETE https://auth.stackbilt.dev/api-keys/key-uuid \ + -H "Authorization: Bearer ea_your_admin_key" +``` + +**Response:** + +```json +{ + "success": true +} +``` + +## Rotation + +To rotate a key: + +1. Generate a new key with the same scopes and project binding +2. Update your application configuration to use the new key +3. Verify the new key works by making a test request +4. Revoke the old key + +There is no atomic rotation endpoint -- this two-step process ensures zero downtime. Both keys remain valid until the old one is explicitly revoked. + +For img-forge keys, the gateway provides an atomic rotation endpoint: + +``` +POST https://imgforge.stackbilt.dev/v2/tenants/:id/rotate +``` + +This invalidates the current key and returns a new one in a single request. + +## Scope Reference + +| Scope | Description | +|-------|-------------| +| `ai:invoke` | Call MCP tools and scaffold endpoints | +| `read` | Read flows, images, and project data | +| `generate` | Create image generation jobs (img-forge) | + +When no scopes are specified at creation, the key inherits all scopes available to the creating user's role. + +## Access Control + +API key operations are governed by edge-auth's policy engine: + +- **Creating org-wide keys** (no `projectId`) requires org admin role or a service principal. Project-scoped keys or member-role users cannot mint org-wide keys. +- **Creating project-scoped keys** requires at least member access to the project's org. +- **Revoking keys** requires access to the key's org (and project, if project-scoped). +- **Listing keys** requires read access to the org. + +All API key operations are audit-logged with risk level, principal identity, and outcome. + +## Security + +- Keys are hashed with SHA-256 before storage. Raw keys exist only in memory during generation and in the creation response. +- Validation uses constant-time comparison to prevent timing attacks. +- All denied requests return a uniform 403 response -- the system does not distinguish between nonexistent keys, revoked keys, and unauthorized access. +- `last_used_at` is updated on each successful validation for monitoring. +- Keys can optionally carry an `expires_at` timestamp for automatic expiration. diff --git a/src/content/docs/billing.md b/src/content/docs/billing.md new file mode 100644 index 0000000..e57259e --- /dev/null +++ b/src/content/docs/billing.md @@ -0,0 +1,254 @@ +--- +title: "Billing & Subscriptions" +description: "Stripe-powered billing for Stackbilt services. Checkout sessions, customer portal, tier management, and webhook-driven subscription lifecycle." +section: "platform" +order: 11 +color: "#10b981" +tag: "11" +--- + +# Billing & Subscriptions + +Stackbilt uses Stripe for all billing. Subscriptions are managed through edge-auth (`auth.stackbilt.dev`), which acts as the centralized billing gateway for every project in the platform. + +## Plan Tiers + +Flat pricing. No credits, no tokens, no per-action charges. + +| | Free | Pro | Team | +|---|---|---|---| +| **Price** | $0 | $29/mo | $19/seat/mo | +| **Scaffolds/mo** | 3 | 50 | 50/seat | +| **Images/mo** | 5 | 100 | Pooled | +| **Phase 1 (deterministic)** | Yes | Yes | Yes | +| **Phase 2 (LLM polish)** | Yes | Yes | Yes | +| **Quality tiers (img-forge)** | Draft-Premium | All 5 | All 5 | +| **Stacks** | Cloudflare Workers | All supported | All supported | +| **Governance output** | Yes | Yes | Yes | + +Every plan includes full governance output (threat analysis, ADRs, test plans) with every scaffold. + +## Checkout Flow + +### How It Works + +1. User clicks "Upgrade to Pro" on `stackbilder.com/pricing` +2. The frontend calls `POST /billing/checkout` on edge-auth with the Stripe price ID +3. Edge-auth creates a Stripe Checkout session with the org's customer ID +4. User is redirected to Stripe's hosted checkout page +5. After successful payment, Stripe sends a `checkout.session.completed` webhook +6. Edge-auth updates the tenant's tier and provisions new entitlements + +### REST API + +``` +POST https://auth.stackbilt.dev/billing/checkout +``` + +Requires an authenticated session with org-level `create` access. + +**Request body:** + +```json +{ + "orgId": "org_stackbilt", + "priceId": "price_xxx", + "projectId": "prop_stackbilder", + "tenantId": "tenant-uuid", + "successUrl": "https://stackbilder.com/settings?checkout=success", + "cancelUrl": "https://stackbilder.com/pricing" +} +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `orgId` | string | Yes | Organization to bill | +| `priceId` | string | Yes | Stripe price ID for the plan | +| `projectId` | string | No | Project scope (for per-project Stripe accounts) | +| `tenantId` | string | No | Tenant scope | +| `successUrl` | string | Yes | Redirect URL after successful checkout | +| `cancelUrl` | string | Yes | Redirect URL if user cancels | + +**Response:** + +```json +{ + "url": "https://checkout.stripe.com/c/pay/cs_xxx" +} +``` + +Redirect the user to the returned URL to complete checkout. + +### RPC (Service Binding) + +```typescript +const { url } = await env.AUTH_SERVICE.createCheckoutSession({ + orgId: "org_stackbilt", + priceId: "price_xxx", + successUrl: "https://stackbilder.com/settings?checkout=success", + cancelUrl: "https://stackbilder.com/pricing", +}); +``` + +## Customer Portal + +The Stripe Customer Portal lets users manage their subscription without leaving the Stackbilt experience: update payment methods, view invoices, cancel, or change plans. + +``` +POST https://auth.stackbilt.dev/billing/portal +``` + +**Request body:** + +```json +{ + "orgId": "org_stackbilt", + "returnUrl": "https://stackbilder.com/settings" +} +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `orgId` | string | Yes | Organization with an active billing account | +| `projectId` | string | No | Project scope (for per-project Stripe accounts) | +| `returnUrl` | string | Yes | URL to redirect to after portal session | + +**Response:** + +```json +{ + "url": "https://billing.stripe.com/p/session/xxx" +} +``` + +If the organization has no Stripe customer ID (never subscribed), the endpoint returns 403. + +## Subscription Lifecycle + +Edge-auth handles the full subscription lifecycle through Stripe webhooks. All webhook events are signature-verified and idempotent (duplicate events are safely ignored). + +### Webhook Events + +| Event | Handler | +|-------|---------| +| `checkout.session.completed` | Creates or upgrades the tenant tier, provisions entitlements, sends confirmation email | +| `customer.subscription.updated` | Reconciles tier based on the subscription's price metadata | +| `customer.subscription.deleted` | Downgrades tenant to free tier, clears subscription ID | +| `invoice.payment_failed` | Marks tenant as payment delinquent | +| `invoice.payment_succeeded` | Clears payment delinquent flag | + +### Tier Reconciliation + +When a subscription event arrives, edge-auth: + +1. Looks up the `tier` metadata on the Stripe price object +2. Updates the tenant's tier in the database +3. If the tier changed, publishes a tier change event to the `edge-auth-tier-changes` queue +4. Downstream services (Stackbilder, img-forge) consume the queue to update their entitlement caches + +Tier mapping is driven entirely by Stripe price metadata -- add `tier: "pro"` to a Stripe price, and edge-auth handles the rest. + +### Payment Delinquency + +When `invoice.payment_failed` fires, the tenant is marked delinquent. Delinquent tenants retain their tier but may see degraded service (e.g., warning banners, blocked new scaffolds). When payment succeeds, the delinquent flag is cleared automatically. + +## Entitlements & Quotas + +Each tier maps to a set of feature entitlements with monthly quotas. Entitlements are provisioned automatically when a user signs up (free tier) or when their subscription tier changes. + +### Checking Quota + +```typescript +const status = await env.AUTH_SERVICE.checkQuota({ + tenantId: "tenant-uuid", + feature: "scaffolds", + amount: 1, +}); +// status.allowed, status.remaining, status.limit +``` + +### Consuming Quota + +Quota consumption uses a two-phase commit pattern: + +1. **Reserve** -- `consumeQuota` decrements the quota and returns a `reservationId` +2. **Commit or refund** -- `commitOrRefundQuota` finalizes the reservation + +```typescript +// Reserve +const result = await env.AUTH_SERVICE.consumeQuota({ + tenantId: "tenant-uuid", + feature: "scaffolds", + amount: 1, +}); + +if (!result.success) { + // Quota exceeded -- show upgrade CTA +} + +// ... perform the operation ... + +// Commit on success, refund on failure +await env.AUTH_SERVICE.commitOrRefundQuota( + result.reservationId, + operationSucceeded ? "success" : "failed", +); +``` + +### Viewing Entitlements + +```typescript +const view = await env.AUTH_SERVICE.getEntitlements(tenantId, userId); +// view.plan, view.features.scaffolds.remaining, etc. +``` + +Users see "X scaffolds remaining" at 80% usage. At 100%, a hard wall with an upgrade CTA is shown. + +## Fractal Billing + +Edge-auth supports per-project Stripe accounts. Each project can specify its own `stripe_config` in the database with a dedicated Stripe secret key and webhook secret. This enables: + +- **FoodFiles** connects to edge-auth under its own Stripe account +- **Stackbilder** uses the global Stripe account +- New projects can be onboarded with their own billing relationship + +When a project has a `stripe_config`, billing operations (checkout, portal, webhook verification) use the project's Stripe credentials. When no config is present, they fall back to the global `STRIPE_SECRET_KEY`. + +## Promotion Codes + +Admins can create and manage Stripe promotion codes through edge-auth: + +### Create a Promo Code + +```typescript +const promo = await env.AUTH_SERVICE.createPromoCode({ + code: "LAUNCH50", + percentOff: 50, + duration: "repeating", + durationInMonths: 3, + maxRedemptions: 100, +}); +``` + +### List Active Promo Codes + +```typescript +const { codes } = await env.AUTH_SERVICE.listPromoCodes(); +``` + +### Revoke a Promo Code + +```typescript +await env.AUTH_SERVICE.revokePromoCode("promo_xxx"); +``` + +Promotion codes are applied during Stripe Checkout (`allow_promotion_codes: true`). When a checkout session completes with a promo code, edge-auth logs the redemption in the `promo_redemptions` table for analytics. + +## Audit Trail + +Every billing operation is audit-logged with: + +- **Risk level**: `EXTERNAL_SIDE_EFFECT` (Stripe interactions) +- **Principal**: The authenticated user or service making the request +- **Action**: `billing.checkout.create`, `billing.portal.create`, `stripe.webhook`, etc. +- **Outcome**: Success or failure with context diff --git a/src/content/docs/ecosystem.md b/src/content/docs/ecosystem.md index d149fa9..8eac8a1 100644 --- a/src/content/docs/ecosystem.md +++ b/src/content/docs/ecosystem.md @@ -126,7 +126,7 @@ All services use edge-auth (`auth.stackbilt.dev`) for centralized authentication - **Session cookies** — `better-auth.session_token`, validated via RPC service binding - **API keys** — `ea_*`, `sb_live_*`, `sb_test_*` prefixes for programmatic access -The platform frontend (`stackbilder.com`) validates sessions via an RPC binding to edge-auth — near-zero latency, no HTTP hop. +See [API Key Management](/api-keys) for generation, rotation, and revocation. The platform frontend (`stackbilder.com`) validates sessions via an RPC binding to edge-auth — near-zero latency, no HTTP hop. ## Pricing @@ -138,7 +138,7 @@ Flat tiers. No credits, no tokens, no per-action charges. | Pro | 50 | 100 | $29/mo | | Team | 50/seat | Pooled | $19/seat/mo | -Every plan includes full governance output. See [stackbilder.com/pricing](https://stackbilder.com/pricing). +Every plan includes full governance output. See [stackbilder.com/pricing](https://stackbilder.com/pricing) and [Billing & Subscriptions](/billing) for checkout flow and subscription management. ## Multi-Stack Roadmap diff --git a/src/content/docs/getting-started.md b/src/content/docs/getting-started.md index 73956c6..e57f117 100644 --- a/src/content/docs/getting-started.md +++ b/src/content/docs/getting-started.md @@ -1,12 +1,59 @@ --- -title: "Charter Kit" -description: "AI-first developer framework for governance and project scaffolding" +title: "Getting Started" +description: "Sign up, explore the platform, and install the governance CLI in under five minutes." section: "charter" order: 2 color: "#2ea043" tag: "02" --- +# Getting Started + +## Sign Up + +Stackbilder uses OAuth for instant account creation -- no waitlist, no invite codes. Sign up at [stackbilder.com/login](https://stackbilder.com/login) using either provider: + +- **GitHub** -- recommended for developers +- **Google** -- alternative for non-GitHub users + +### What Happens on First Sign-In + +1. Click "Sign in with GitHub" (or Google) on `stackbilder.com/login` +2. You are redirected to `auth.stackbilt.dev` for OAuth authentication +3. The OAuth provider authenticates you and redirects back +4. Edge-auth automatically provisions your account: + - Creates your **organization** (named after your profile) + - Creates a **default project** under the org + - Creates a **personal tenant** with free-tier entitlements + - Provisions monthly quotas (3 scaffolds, 5 images) +5. You land on the Stackbilder dashboard, ready to create your first scaffold + +No email verification step, no approval queue. The entire flow takes under 10 seconds. + +### Session Management + +After sign-in, a `better-auth.session_token` cookie is set. This cookie authenticates all subsequent requests to Stackbilder, img-forge, and the MCP gateway automatically. Sessions are validated via edge-auth's RPC binding with near-zero latency. + +## Your First Scaffold + +Once signed in, create your first governed codebase: + +1. Go to [stackbilder.com](https://stackbilder.com) +2. Describe what you want to build in plain language (e.g., "A REST API for managing subscriptions with Stripe") +3. Stackbilder classifies your intention and generates a complete project skeleton in ~20ms +4. Download the scaffold -- it includes your code structure, config files, and the full `.ai/` governance suite + +Every scaffold ships with governance output: +- `.ai/threat-model.md` -- STRIDE-based security analysis specific to your architecture +- `.ai/adr-*.md` -- Architectural decision records +- `.ai/test-plan.md` -- Test specifications with coverage targets + +### Upgrading to Pro + +The free tier includes 3 scaffolds and 5 images per month. To unlock 50 scaffolds, 100 images, Phase 2 LLM polish, and all image quality tiers, upgrade to Pro at $29/mo from [stackbilder.com/pricing](https://stackbilder.com/pricing). See [Billing & Subscriptions](/billing) for details. + +--- + # Charter Kit [![npm version](https://img.shields.io/npm/v/@stackbilt/cli?label=charter&color=5F7FFF&style=for-the-badge)](https://www.npmjs.com/package/@stackbilt/cli) diff --git a/src/content/docs/platform.md b/src/content/docs/platform.md index bbe2d53..fcebbef 100644 --- a/src/content/docs/platform.md +++ b/src/content/docs/platform.md @@ -64,6 +64,8 @@ Flat pricing. No credits, no tokens, no per-action charges. Usage is enforced via invisible quotas through edge-auth. Users see "X scaffolds remaining" at 80% usage, with a hard wall and upgrade CTA at 100%. +For checkout flow, subscription management, and quota details, see [Billing & Subscriptions](/billing). For programmatic access via API keys, see [API Key Management](/api-keys). + ## Supported Stacks Cloudflare Workers is the currently available stack. Multi-stack expansion is on the roadmap: