From 8774f1843eaeb454a92ef37fa74450e624aea649 Mon Sep 17 00:00:00 2001 From: Ayush Rodrigues Date: Mon, 2 Mar 2026 22:23:20 +0000 Subject: [PATCH] docs wip --- apps/docs/mintlify/cli/commands.mdx | 259 +++++++++++++ apps/docs/mintlify/cli/config.mdx | 364 ++++++++++++++++++ apps/docs/mintlify/cli/getting-started.mdx | 121 ++++++ apps/docs/mintlify/docs.json | 36 +- .../documentation/customers/balances.mdx | 196 ---------- .../customers/balances/balance-stacking.mdx | 71 ++++ .../customers/balances/managing-balances.mdx | 186 +++++++++ .../customers/balances/overview.mdx | 105 +++++ .../subscriptions/accepting-payments.mdx | 168 ++++++++ .../subscriptions/managing-subscriptions.mdx | 103 +++++ .../customers/subscriptions/overview.mdx | 36 ++ .../external-providers/vercel-marketplace.mdx | 70 ++++ .../getting-started/migration.mdx | 88 +++++ apps/docs/mintlify/documentation/webhooks.mdx | 129 +++++++ apps/docs/mintlify/welcome.mdx | 52 ++- 15 files changed, 1775 insertions(+), 209 deletions(-) create mode 100644 apps/docs/mintlify/cli/commands.mdx create mode 100644 apps/docs/mintlify/cli/config.mdx create mode 100644 apps/docs/mintlify/cli/getting-started.mdx delete mode 100644 apps/docs/mintlify/documentation/customers/balances.mdx create mode 100644 apps/docs/mintlify/documentation/customers/balances/balance-stacking.mdx create mode 100644 apps/docs/mintlify/documentation/customers/balances/managing-balances.mdx create mode 100644 apps/docs/mintlify/documentation/customers/balances/overview.mdx create mode 100644 apps/docs/mintlify/documentation/customers/subscriptions/accepting-payments.mdx create mode 100644 apps/docs/mintlify/documentation/customers/subscriptions/managing-subscriptions.mdx create mode 100644 apps/docs/mintlify/documentation/customers/subscriptions/overview.mdx create mode 100644 apps/docs/mintlify/documentation/external-providers/vercel-marketplace.mdx create mode 100644 apps/docs/mintlify/documentation/getting-started/migration.mdx create mode 100644 apps/docs/mintlify/documentation/webhooks.mdx diff --git a/apps/docs/mintlify/cli/commands.mdx b/apps/docs/mintlify/cli/commands.mdx new file mode 100644 index 000000000..c9a2a632c --- /dev/null +++ b/apps/docs/mintlify/cli/commands.mdx @@ -0,0 +1,259 @@ +--- +title: "Command reference" +description: "Every command, flag, and option available in the atmn CLI" +--- + +## Global flags + +These flags work with any command: + +| Flag | Description | +|------|-------------| +| `-p, --prod` | Target production instead of sandbox | +| `-l, --local` | Use `localhost:8080` API server | +| `--headless` | Force non-interactive mode (for CI/agents) | +| `-c, --config ` | Path to config file (default: `autumn.config.ts`) | +| `-v, --version` | Show CLI version | + +Flags can be combined -- for example, `atmn push -lp` targets production on a local API server. + +## Authentication + +### `atmn login` + +Authenticate with Autumn via OAuth. Opens your browser, lets you select an organization, and saves sandbox + production API keys to `.env`. + +```bash +atmn login +``` + +In non-TTY environments (CI), it prints a URL you can open manually. + +### `atmn logout` + +Remove `AUTUMN_SECRET_KEY` and `AUTUMN_PROD_SECRET_KEY` from your `.env` file. + +```bash +atmn logout +``` + +### `atmn env` + +Show your current organization and environment: + +```bash +atmn env +``` + +``` +Organization: Acme Corp +Slug: acme-corp +Environment: Sandbox +``` + +## Configuration + +### `atmn init` + +Create an `autumn.config.ts` from a starter template. Prompts for login if you haven't authenticated yet. + +```bash +atmn init +``` + +### `atmn push` + +Push your local `autumn.config.ts` to Autumn. + +```bash +atmn push [options] +``` + +| Flag | Description | +|------|-------------| +| `-y, --yes` | Auto-confirm all prompts | + +The CLI compares your local config with what's in Autumn and shows a summary of changes before applying. If plans with existing customers are modified, it will prompt about versioning. + +### `atmn pull` + +Pull plans and features from Autumn into your local `autumn.config.ts`. + +```bash +atmn pull [options] +``` + +| Flag | Description | +|------|-------------| +| `-f, --force` | Overwrite config instead of smart in-place update | + +By default, `pull` does a smart in-place update -- it adds new features and plans, updates existing ones, and removes deleted ones while preserving your formatting. Use `--force` to overwrite the entire file. + +`pull` also generates an `@useautumn-sdk.d.ts` file with typed `FeatureIds` and `PlanIds` for IDE autocompletion. + +### `atmn preview` + +Render a pricing table from your local config without making any API calls. + +```bash +atmn preview [options] +``` + +| Flag | Description | +|------|-------------| +| `--plan ` | Preview a specific plan | +| `--currency ` | Currency for display (default: `USD`) | + +### `atmn nuke` + +Permanently delete all data in your **sandbox**. This command refuses to run with `--prod`. + +```bash +atmn nuke +``` + +| Flag | Description | +|------|-------------| +| `--dangerously-skip-all-confirmation-prompts` | Skip all safety prompts | + + +This is irreversible. The flag name is intentionally long to prevent accidental use. + + +## Data browsing + +These commands open a full interactive TUI for browsing and inspecting your Autumn data. Use the `--headless` flag to get structured data instead. + +### `atmn customers` + +```bash +atmn customers [options] +``` + +| Flag | Description | +|------|-------------| +| `--id ` | Get a specific customer | +| `--search ` | Filter customers | +| `--page ` | Page number (default: `1`) | +| `--limit ` | Results per page (default: `50`) | +| `--format ` | Output: `text`, `json`, `csv` (default: `text`) | + +### `atmn plans` + +```bash +atmn plans [options] +``` + +| Flag | Description | +|------|-------------| +| `--id ` | Get a specific plan | +| `--search ` | Filter plans | +| `--include-archived` | Include archived plans | +| `--page ` | Page number (default: `1`) | +| `--limit ` | Results per page (default: `50`) | +| `--format ` | Output: `text`, `json`, `csv` (default: `text`) | + + +`atmn products` is an alias for `atmn plans`. + + +### `atmn features` + +```bash +atmn features [options] +``` + +| Flag | Description | +|------|-------------| +| `--id ` | Get a specific feature | +| `--search ` | Filter features | +| `--include-archived` | Include archived features | +| `--page ` | Page number (default: `1`) | +| `--limit ` | Results per page (default: `50`) | +| `--format ` | Output: `text`, `json`, `csv` (default: `text`) | + +### `atmn events` + +```bash +atmn events [options] +``` + +| Flag | Description | +|------|-------------| +| `--customer ` | Filter by customer | +| `--feature ` | Filter by feature (comma-separated for multiple) | +| `--time ` | Time range: `24h`, `7d`, `30d`, `90d` (default: `7d`) | +| `--mode ` | `list` or `aggregate` (default: `list`) | +| `--bin ` | Bin size for aggregate: `hour`, `day`, `month` | +| `--group-by ` | Group by property in aggregate mode | +| `--page ` | Page number (default: `1`) | +| `--limit ` | Results per page (default: `100`) | +| `--format ` | Output: `text`, `json`, `csv` (default: `text`) | + +## Configuration + +### `atmn config` + +View and manage persistent CLI settings. + +```bash +atmn config # Show help and config file location +atmn config --global # Same as above +atmn config --global # Read a setting +atmn config --global # Write a setting +``` + +Running `atmn config` with no arguments shows the full path to your config file, supported keys, and usage info. + +| Flag | Description | +|------|-------------| +| `-g, --global` | Use global config | + +#### Available keys + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `noDeclarationFile` | `boolean` | `false` | Skip generating `@useautumn-sdk.d.ts` on `atmn pull` | + +#### Priority order + +Settings are resolved in this order: **CLI flag** → **global config** → **default value**. For example, `--no-declaration-file` on `atmn pull` always takes priority over the global `noDeclarationFile` setting. + +#### Config file location + +Running `atmn config` or `atmn config --global` (with no key) prints the exact path to your config file on disk. + +| OS | Path | +|----|------| +| macOS | `~/Library/Preferences/atmn/config.json` | +| Linux | `~/.config/atmn/config.json` (or `$XDG_CONFIG_HOME`) | +| Windows | `%APPDATA%\atmn\config.json` | + +## Utilities + +### `atmn dashboard` + +Open the Autumn dashboard in your browser. + +```bash +atmn dashboard +``` + +### `atmn version` + +Print the CLI version. Alias: `atmn v`. + +```bash +atmn version +``` + +## Headless mode + +The CLI automatically detects non-TTY environments and switches to headless mode with plain text output and no interactive prompts. You can also force it with `--headless`. + +### Exit codes + +| Code | Meaning | +|------|---------| +| `0` | Success | +| `1` | Error (network, auth, validation, or confirmation required) | diff --git a/apps/docs/mintlify/cli/config.mdx b/apps/docs/mintlify/cli/config.mdx new file mode 100644 index 000000000..38cdce681 --- /dev/null +++ b/apps/docs/mintlify/cli/config.mdx @@ -0,0 +1,364 @@ +--- +title: "Configuration reference" +description: "Define features, plans, and pricing in autumn.config.ts" +--- + +Your `autumn.config.ts` file is the source of truth for your pricing. It exports features and plans using helper functions from the `atmn` package. + +```ts autumn.config.ts +import { feature, plan, planFeature } from 'atmn'; + +export const messages = feature({ ... }); +export const pro = plan({ ... }); +``` + +Push changes with `atmn push`, or pull existing config with `atmn pull`. + +## Features + +Features define what can be gated, metered, or billed in your app. + +### `feature(config)` + + + Unique identifier used in API calls (`check`, `track`, etc). + + + + Display name shown in the dashboard and billing UI. + + + + `"boolean"` | `"metered"` | `"credit_system"` + + + + **Required for `metered` features.** + - `true` -- usage is consumed (messages, API calls, credits) + - `false` -- usage is ongoing (seats, storage, workspaces) + + + + **Required for `credit_system` features.** Maps metered features to credit costs. + + Each entry: `{ metered_feature_id: string, credit_cost: number }` + + +### Feature types + +**Boolean** -- simple on/off flag: + +```ts +export const sso = feature({ + id: 'sso', + name: 'SSO Authentication', + type: 'boolean', +}); +``` + +**Metered, consumable** -- used up and replenished (messages, API calls): + +```ts +export const messages = feature({ + id: 'messages', + name: 'Messages', + type: 'metered', + consumable: true, +}); +``` + +**Metered, non-consumable** -- ongoing usage (seats, storage): + +```ts +export const seats = feature({ + id: 'seats', + name: 'Seats', + type: 'metered', + consumable: false, +}); +``` + +**Credit system** -- maps multiple metered features to credit costs: + +```ts +export const basicModel = feature({ + id: 'basic_model', + name: 'Basic Model', + type: 'metered', + consumable: true, +}); + +export const premiumModel = feature({ + id: 'premium_model', + name: 'Premium Model', + type: 'metered', + consumable: true, +}); + +export const credits = feature({ + id: 'credits', + name: 'AI Credits', + type: 'credit_system', + credit_schema: [ + { metered_feature_id: basicModel.id, credit_cost: 1 }, + { metered_feature_id: premiumModel.id, credit_cost: 5 }, + ], +}); +``` + + +If you set the price per credit to 1 cent, credits become monetary credits (eg, 5 credits = $0.05 per premium message). + + +## Plans + +Plans combine features with pricing to create your subscription tiers, add-ons, and top-ups. + +### `plan(config)` + + + Unique identifier used in checkout and subscription APIs. + + + + Display name shown in pricing tables and billing. + + + + Base subscription price: + - `amount: number` -- price amount (eg, `20` for $20) + - `interval: string` -- `"month"` | `"quarter"` | `"semi_annual"` | `"year"` | `"one_off"` + + + + Array of `planFeature()` objects defining what's included. + + + + Automatically assign this plan to new customers. Typically used for free plans. + + + + Allow this plan to be purchased alongside other plans (instead of replacing them). + + + + Free trial before billing starts: + - `duration_length: number` -- eg, `14` + - `duration_type: string` -- `"day"` | `"month"` | `"year"` + - `card_required: boolean` -- whether a card is needed to start the trial + + + + Group related plans together. Plans in the same group replace each other on upgrade/downgrade. + + +## Plan features + +Plan features define what each plan includes -- usage limits, pricing, and billing behavior. + +### `planFeature(config)` + + + The `id` of the feature to include. + + + + Amount included for free. Omit for boolean features. + + + + Grant unlimited usage of this feature. + + + + How often the included amount resets: + - `interval: string` -- `"hour"` | `"day"` | `"week"` | `"month"` | `"quarter"` | `"semi_annual"` | `"year"` + - `interval_count: number` -- defaults to `1` + + + + Pricing for usage beyond the included amount. See [pricing patterns](#pricing-patterns) below. + + + + How to handle mid-cycle quantity changes: + - `on_increase:` `"prorate"` | `"charge_immediately"` + - `on_decrease:` `"prorate"` | `"refund_immediately"` | `"no_action"` + + + + Carry unused balance forward: + - `max: number` -- maximum rollover amount + - `expiry_duration_type:` `"month"` | `"forever"` + - `expiry_duration_length: number` -- ignored if type is `"forever"` + + +### Pricing patterns + +The `price` object on a plan feature supports different billing models: + +**Usage-based** -- charge based on actual usage: + +```ts +planFeature({ + feature_id: seats.id, + included: 5, + price: { + amount: 10, + interval: 'month', + billing_method: 'usage_based', + billing_units: 1, + }, +}) +``` + +**Prepaid** -- customer buys a fixed quantity upfront: + +```ts +planFeature({ + feature_id: credits.id, + price: { + amount: 5, + billing_units: 100, + billing_method: 'prepaid', + }, +}) +``` + +**Tiered** -- price changes based on usage volume: + +```ts +planFeature({ + feature_id: apiCalls.id, + price: { + tiers: [ + { to: 1000, amount: 0.01 }, + { to: 10000, amount: 0.008 }, + { to: 'inf', amount: 0.005 }, + ], + billing_method: 'usage_based', + interval: 'month', + }, +}) +``` + +#### Price fields + + + Price per `billing_units`. Mutually exclusive with `tiers`. + + + + Tiered pricing. Each entry: `{ to: number | "inf", amount: number }`. Mutually exclusive with `amount`. + + + + `"usage_based"` | `"prepaid"` + + + + `"week"` | `"month"` | `"quarter"` | `"semi_annual"` | `"year"`. Omit for one-time charges. Not needed if the plan feature has a top-level `reset`. + + + + Units per price. Eg, $5 per 100 credits = `amount: 5, billing_units: 100`. + + + + Maximum quantity that can be purchased. + + +## Full example + +A complete config with a free plan, a paid plan with a trial, and a credits top-up add-on: + +```ts autumn.config.ts +import { feature, plan, planFeature } from 'atmn'; + +// Features +export const messages = feature({ + id: 'messages', + name: 'Messages', + type: 'metered', + consumable: true, +}); + +export const seats = feature({ + id: 'seats', + name: 'Seats', + type: 'metered', + consumable: false, +}); + +export const sso = feature({ + id: 'sso', + name: 'SSO', + type: 'boolean', +}); + +// Plans +export const free = plan({ + id: 'free', + name: 'Free', + auto_enable: true, + items: [ + planFeature({ + feature_id: messages.id, + included: 5, + reset: { interval: 'month' }, + }), + planFeature({ + feature_id: seats.id, + included: 1, + }), + ], +}); + +export const pro = plan({ + id: 'pro', + name: 'Pro', + price: { amount: 20, interval: 'month' }, + free_trial: { + duration_length: 14, + duration_type: 'day', + card_required: true, + }, + items: [ + planFeature({ + feature_id: messages.id, + included: 1000, + reset: { interval: 'month' }, + }), + planFeature({ + feature_id: seats.id, + included: 5, + price: { + amount: 10, + interval: 'month', + billing_method: 'usage_based', + billing_units: 1, + }, + }), + planFeature({ + feature_id: sso.id, + }), + ], +}); + +export const topUp = plan({ + id: 'top_up', + name: 'Message Top-Up', + add_on: true, + items: [ + planFeature({ + feature_id: messages.id, + price: { + amount: 5, + billing_units: 100, + billing_method: 'prepaid', + }, + }), + ], +}); +``` diff --git a/apps/docs/mintlify/cli/getting-started.mdx b/apps/docs/mintlify/cli/getting-started.mdx new file mode 100644 index 000000000..661f98c91 --- /dev/null +++ b/apps/docs/mintlify/cli/getting-started.mdx @@ -0,0 +1,121 @@ +--- +title: "Getting started" +description: "Install the CLI, authenticate, and sync your pricing config" +--- + +The `atmn` CLI lets you define your pricing plans in code via an `autumn.config.ts` file, and sync them to Autumn with a single command. + +## Installation + +Run the CLI directly with your package manager: + + + +```bash bunx +bunx atmn +``` + +```bash pnpm +pnpm dlx atmn +``` + +```bash npx +npx atmn +``` + + + +## Login + +Authenticate with your Autumn account: + +```bash +bunx atmn login +``` + +This opens your browser, lets you pick an organization, and saves API keys for both sandbox and production to your `.env` file: + +```bash .env +AUTUMN_SECRET_KEY=am_sk_test_... +AUTUMN_PROD_SECRET_KEY=am_sk_live_... +``` + + +You can verify your setup at any time with `bunx atmn env`, which shows your current organization and environment. + + +## Initialize a project + +Run `atmn init` in your project root to create an `autumn.config.ts` file: + +```bash +bunx atmn init +``` + +You'll be prompted to choose a starter template: + +| Template | Pricing model | +|----------|--------------| +| **T3 Chat** | Freemium with message limits and a credits add-on | +| **Railway** | Credit-based infrastructure pricing with overage | +| **Linear** | Per-seat pricing with team limits | +| **OpenAI** | Credit system mapping multiple AI models | + +Pick whichever is closest to your use case, or start from scratch and build your own using the [config reference](/api-reference/cli/config). + +## Push and pull + +Once you have an `autumn.config.ts`, sync it with Autumn: + +```bash +# Push local config to Autumn +bunx atmn push + +# Pull remote config into your local file +bunx atmn pull +``` + +`push` reads your config file, compares it with what's in Autumn, and applies the changes. In interactive mode you'll see a summary of what will be created, updated, or deleted before confirming. + +`pull` fetches your plans and features from Autumn and writes them into your local `autumn.config.ts`. If the file already exists, it does a smart in-place update that preserves your local formatting and comments where possible. + + +Use `bunx atmn pull` to generate an `autumn.config.ts` from plans you've already created in the dashboard. + + +## Preview locally + +You can preview your plans without pushing anything: + +```bash +bunx atmn preview +``` + +This renders a pricing table from your local config. + +## Environments + +By default, all commands target your **sandbox** environment. Add the `-p` flag to target production: + +```bash +# Push to production +bunx atmn push -p + +# Pull from production +bunx atmn pull -p +``` + + +Pushing to production will prompt for confirmation. Use `--yes` to skip the prompt automatically. + + +**Next: Configuration reference** + +Learn how to define features, plans, and pricing in your `autumn.config.ts`. + + + Complete reference for features, plans, and plan features + diff --git a/apps/docs/mintlify/docs.json b/apps/docs/mintlify/docs.json index ee60314ab..a5735050b 100644 --- a/apps/docs/mintlify/docs.json +++ b/apps/docs/mintlify/docs.json @@ -45,7 +45,7 @@ "groups": [ { "group": " ", - "pages": ["welcome"] + "pages": ["welcome", "documentation/getting-started/migration"] }, { "group": "Getting Started", @@ -76,19 +76,36 @@ { "group": "Manage Customers", "pages": [ + { + "group": "Subscriptions", + "pages": [ + "documentation/customers/subscriptions/overview", + "documentation/customers/subscriptions/accepting-payments", + "documentation/customers/subscriptions/managing-subscriptions" + ] + }, + { + "group": "Balances", + "pages": [ + "documentation/customers/balances/overview", + "documentation/customers/balances/balance-stacking", + "documentation/customers/balances/managing-balances" + ] + }, "documentation/customers/check", "documentation/customers/tracking-usage", - "documentation/customers/balances", "documentation/customers/feature-entities", - "documentation/customers/attaching-plans", - "documentation/customers/updating-subscriptions", "documentation/customers/creating-customers", "documentation/customers/managing-customers" ] }, { "group": "Additional Resources", - "pages": ["documentation/external-providers/revenuecat"] + "pages": [ + "documentation/webhooks", + "documentation/external-providers/revenuecat", + "documentation/external-providers/vercel-marketplace" + ] } ] }, @@ -104,7 +121,7 @@ }, { "tab": "React", - "icon": "image", + "icon": "react", "groups": [ { "group": "React Hooks", @@ -122,9 +139,14 @@ } ] }, + { + "tab": "CLI", + "icon": "square-terminal", + "pages": ["cli/getting-started", "cli/config", "cli/commands"] + }, { "tab": "API Reference", - "icon": "rectangle-terminal", + "icon": "display-code", "groups": [ { "group": "Billing", diff --git a/apps/docs/mintlify/documentation/customers/balances.mdx b/apps/docs/mintlify/documentation/customers/balances.mdx deleted file mode 100644 index b6e9411db..000000000 --- a/apps/docs/mintlify/documentation/customers/balances.mdx +++ /dev/null @@ -1,196 +0,0 @@ ---- -title: Balances -description: Learn about feature balances for your metered features ---- - -Each metered feature you create has 3 different fields associated with it per customer: - -1. **Granted**: The total allowance of usage granted to the customer (included + prepaid). -2. **Usage**: The amount of the feature that the customer has used. -3. **Remaining**: The amount of usage that the customer has left (`granted - usage`). - - -If the product item has a `prepaid` price, the granted amount will be dynamically set to the quantity of the product item purchased in advance. - - -## Getting a Customer's Balances - -You can get a customer's balances with the `customers.getOrCreate` method: - - - -```typescript TypeScript -import { Autumn } from "autumn-js"; - -const autumn = new Autumn({ secretKey: "am_sk_test_1234" }); - -const customer = await autumn.customers.getOrCreate({ - customerId: "user_123", -}); - -// Access balances by feature ID -const messages = customer.balances?.messages; -console.log(`${messages?.remaining} / ${messages?.granted} remaining`); -``` - -```python Python -from autumn_sdk import Autumn - -autumn = Autumn("am_sk_test_1234") - -customer = await autumn.customers.get_or_create( - customer_id="user_123" -) - -messages = customer.balances.get("messages") -print(f"{messages.remaining} / {messages.granted} remaining") -``` - -```bash cURL -curl -X POST "https://api.useautumn.com/v1/customers" \ - -H "Authorization: Bearer am_sk_test_1234" \ - -H "Content-Type: application/json" \ - -d '{ "customer_id": "user_123" }' -``` - - - - -```json -{ - "id": "user_123", - "balances": { - "ai-messages": { - "featureId": "ai-messages", - "granted": 100, - "remaining": 40, - "usage": 60, - "unlimited": false, - "overageAllowed": false, - "nextResetAt": 1745193600011 - }, - "seats": { - "featureId": "seats", - "granted": 5, - "remaining": -1, - "usage": 6, - "unlimited": false, - "overageAllowed": true, - "nextResetAt": null - }, - "premium-support": { - "featureId": "premium-support", - "granted": 0, - "remaining": 0, - "usage": 0, - "unlimited": true, - "overageAllowed": false, - "nextResetAt": null - } - } -} -``` - - -## Positive and Negative Balances - -A feature's remaining balance can be positive or negative: - -- **Positive Balance**: The customer has used less than the granted amount — they have usage remaining. -- **Negative Balance**: The customer has used more than the granted amount — they will be billed for overage in the next billing period. - - -Features can only have a negative balance if they have a [usage-based price](/documentation/pricing/plan-features#priced-features) associated with them. - -If a feature does not have a price, its balance will never fall below 0 even if more usage events are sent. - - -## Reset Intervals - -When you create a product item, you'll define a usage reset interval. When the reset interval comes around, `usage` will be reset to 0, and `remaining` will be set back to the `granted` amount. - -Reset intervals can be: `minute`, `hour`, `day`, `week`, `month`, `quarter`, `semi_annual`, or `year`. - -If a feature has a price associated with it, the reset interval will be the same as the billing interval. This means it can be one of the following: `month`, `quarter`, `semi_annual`, or `year`. - -#### No Reset - -Certain features are consumable, and can have balances that are replenished. For example, you may have features like: - -- Credits -- AI messages -- Hours of compute - -Other features are not consumable, and their usage is continuous. For example: - -- Seats -- Workspaces -- Number of compute instances in use - -These features should not have a reset interval, so that their balances are never reset. - - - This is not a hard rule. You may have consumable features like messages, but - want them to last forever. In this case, they should also have a reset - interval of "no reset" - - -You can configure a product item to have no reset interval by selecting "One-off" in the plan editor dashboard. - - - -**Example use case** - -We have a free tier, which gives customers access to 3 seats. -We also have a pro tier, which is charged at $10/seat/month. - -For our free tier, we'd create a product item with: - -- Usage reset: No Reset -- Via API: `interval: null` - -For our pro tier, we'd create a product item with: - -- Usage reset: No Reset -- Billing Interval: Month -- Via API: `interval: month`, and `reset_usage_on_billing: false` - - - -#### Features with multiple intervals - -You may have a pricing model in which a customer can buy the following together: - -- a pro plan with 50 credits per month. -- a top-up add-on that grants 100 credits that don't expire - -In this case you have a feature that shares two intervals: `month` and "no reset". - -Autumn will create 2 separate balances for each of these. You will see each of these in the `customers` route and on the customer details page in the dashboard. - -When you send a usage event, Autumn will deduct from the balance with the shortest reset interval first. - - - If you want to deduct from the balance with the longest reset interval first, - please contact us. - - -## Edge Cases - -There are certain cases in which a feature's balance will diverge from the typical `granted` minus `usage` calculation. - -#### Setting a feature's balance manually - -You can manually edit a users balance via the dashboard or via the API. - -When this happens, the balance will be updated to the new value, but the `granted` and `usage` will not be updated. - -#### Customer has paid for more than they are using - -Let's take a pricing model in which a customer pays $10 per seat per month. At the start of the billing period, they are using 5 seats (`remaining: -5`, `usage: 5`). Then, they remove a seat. - -If `prorate_decrease` is set to `false`, the customer will be paying for 5 seats and using 4 seats (`remaining: -5`, `usage: 4`). This means that our customer has 1 seat available that they have paid for but not using. - -In this case, the balance and usage has diverged. Autumn accounts for this scenario: they can add another seat at any time, which will not be charged for. - -Otherwise, at the start of the next billing period, they usage and balance will synchronize again (`remaining: -4`, `usage: 4`), and they will be billed for 4 seats. diff --git a/apps/docs/mintlify/documentation/customers/balances/balance-stacking.mdx b/apps/docs/mintlify/documentation/customers/balances/balance-stacking.mdx new file mode 100644 index 000000000..5c7fda000 --- /dev/null +++ b/apps/docs/mintlify/documentation/customers/balances/balance-stacking.mdx @@ -0,0 +1,71 @@ +--- +title: "Balance Stacking" +description: "How multiple balances combine and how usage is deducted" +--- + +A single feature can have balances from multiple sources - different plans, add-ons, or standalone grants. + +Autumn combines these into a single parent balance while tracking each source separately in a `breakdown` array, grouped by plan and interval. + +> **Example**
+> A customer has a feature, `messages`, with the following balances: +> - Pro plan: 500 messages per month +> - Top-up add-on: 200 lifetime messages +> +> Their total available balance is 700 `messages`. + +## The Breakdown Array + +Each balance source is tracked separately in the `breakdown` array. This lets you see exactly where the balance came from and how much remains from each source. + +```json expandable +{ + "balances": { + "messages": { + "included_usage": 700, + "balance": 700, + "usage": 0, + "breakdown": [ + { + "id": "ent_abc123", + "product_id": "pro", + "included_usage": 500, + "balance": 500, + "usage": 0, + "interval": "month", + "next_reset_at": 1745193600000 + }, + { + "id": "ent_def456", + "product_id": "top-up", + "included_usage": 200, + "balance": 200, + "usage": 0, + "interval": "one_off", + "next_reset_at": null + } + ] + } + } +} +``` + +## Deduction Order + +When usage is tracked, Autumn deducts from balances in a specific order based on their reset interval. **Shorter intervals are deducted first** by default. + +The order is: `hour` (shortest) > `day` > `week` > `month` > `quarter` > `semi_annual` > `year` > `one_off` (lifetime - never resets). + +This ensures that expiring balances are used before permanent ones. + + +If you need the deduction order reversed (longest interval first), please [contact us](https://discord.gg/STqxY92zuS). + + +> **Example**
+> Suppose a customer has two balances for messages: 500 monthly and 200 lifetime. They have a total of 700 messages.
+> - The customer uses 400 messages. The monthly balance (the shorter interval) is used up first, leaving 100 in monthly and 200 in lifetime (300 total).
+> - The customer uses another 200 messages. The remaining 100 monthly is depleted, and the next 100 is deducted from the lifetime balance. Now, monthly is 0, lifetime is 100 (100 total).
+> - On the next cycle, the monthly balance resets to 500, and the lifetime remains at 100, for a new total of 600.
+ + diff --git a/apps/docs/mintlify/documentation/customers/balances/managing-balances.mdx b/apps/docs/mintlify/documentation/customers/balances/managing-balances.mdx new file mode 100644 index 000000000..8043fcea9 --- /dev/null +++ b/apps/docs/mintlify/documentation/customers/balances/managing-balances.mdx @@ -0,0 +1,186 @@ +--- +title: "Managing Balances" +description: "Create, update, and manage balances via the dashboard or API" +--- + +You can manage customer balances through the Autumn dashboard or programmatically via the API. + +## From the Dashboard + +### Viewing Balances + +1. Go to the [Customers page](https://app.useautumn.com/customers) +2. Click on a customer to view their details +3. Their balances are displayed in the **Balances** section, including breakdown by source + +### Modifying a Balance + +To set or add to a feature's balance: + +1. Navigate to the customer's detail page +2. Under the balances section, click on the feature you want to modify. If there are [stacked balances](/documentation/customers/balance-stacking), choose the one you want to modify. +3. Choose whether to **set the balance** to a specific value or **add to the balance** +4. Enter the amount and save + +## Creating Standalone Balances (API) + +You can use the `/balances/create` endpoint to grant balances independent of any plan, for example to issue one-time promotional credits, referral rewards, or make manual customer adjustments. + +You can also set expiration dates for promotional usage grants and configure reset intervals. + + + +```typescript Node.js +import { Autumn } from "autumn-js"; + +const autumn = new Autumn({ secretKey: "am_sk_..." }); + +await autumn.balances.create({ + customer_id: "user_123", + feature_id: "credits", + granted_balance: 500, + reset: { + interval: "one_off" + } +}); +``` + +```python Python +from autumn import Autumn + +autumn = Autumn(secret_key="am_sk_...") + +autumn.balances.create( + customer_id="user_123", + feature_id="credits", + granted_balance=500, + reset={ + "interval": "one_off" + } +) +``` + +```bash cURL +curl -X POST https://api.useautumn.com/v1/balances/create \ + -H "Authorization: Bearer am_sk_..." \ + -H "Content-Type: application/json" \ + -d '{ + "customer_id": "user_123", + "feature_id": "credits", + "granted_balance": 500, + "reset": { + "interval": "one_off" + } + }' +``` + + + +See the [Create Balance API reference](/api-reference/features/create-balance) for all available parameters. + +## Updating Balances (API) + +Use the `/customers/{customer_id}/balances` endpoint to set balances for a customer. + + + +```typescript Node.js +import { Autumn } from "autumn-js"; + +const autumn = new Autumn({ secretKey: "am_sk_..." }); + +await autumn.customers.updateBalances("user_123", { + balances: [{ feature_id: "credits", balance: 750 }] +}); +``` + +```python Python +from autumn import Autumn + +autumn = Autumn(secret_key="am_sk_...") + +autumn.customers.update_balances( + "user_123", + balances=[{"feature_id": "credits", "balance": 750}] +) +``` + +```bash cURL +curl -X POST https://api.useautumn.com/v1/customers/user_123/balances \ + -H "Authorization: Bearer am_sk_..." \ + -H "Content-Type: application/json" \ + -d '{ + "balances": [{ "feature_id": "credits", "balance": 750 }] + }' +``` + + + +See the [Set Feature Balance API reference](/api-reference/features/set-feature-balances) for all available parameters. + +## Querying Balances + +### Via Get Customer + +Retrieve all balances for a customer: + + + +```typescript Node.js +const customer = await autumn.customers.get("user_123"); +console.log(customer.balances); +``` + +```python Python +customer = autumn.customers.get("user_123") +print(customer.balances) +``` + +```bash cURL +curl https://api.useautumn.com/v1/customers/user_123 \ + -H "Authorization: Bearer am_sk_..." +``` + + + +See the [Get Customer API reference](/api-reference/customers/get-customer) for the full response schema. + +### Via Check Endpoint + +Check access and get the current balance for a specific feature: + + + +```typescript Node.js +const result = await autumn.check({ + customer_id: "user_123", + feature_id: "credits" +}); + +console.log(result.allowed); +console.log(result.balance); +``` + +```python Python +result = autumn.check( + customer_id="user_123", + feature_id="credits" +) + +print(result.allowed) +print(result.balance) +``` + +```bash cURL +curl -X POST https://api.useautumn.com/v1/check \ + -H "Authorization: Bearer am_sk_..." \ + -H "Content-Type: application/json" \ + -d '{ + "customer_id": "user_123", + "feature_id": "credits" + }' +``` + + + +See the [Check API reference](/api-reference/core/check) for more details. diff --git a/apps/docs/mintlify/documentation/customers/balances/overview.mdx b/apps/docs/mintlify/documentation/customers/balances/overview.mdx new file mode 100644 index 000000000..8df65e969 --- /dev/null +++ b/apps/docs/mintlify/documentation/customers/balances/overview.mdx @@ -0,0 +1,105 @@ +--- +title: "Balances" +description: "Understanding how feature balances work in Autumn" +--- + +Balances determine what features a customer can use, and track how much they have used. + +Balances are created in two ways: + +1. **Automatically from plans**: When a plan is attached to a customer, each feature in the plan becomes a balance for that customer. +2. **Standalone via API**: You can create balances directly using the API, independent of any plan. See [Managing Balances](/documentation/customers/managing-balances) for details. + +```mermaid +flowchart LR + F[Feature] -->|added to plan| PF[Plan Feature] + PF -->|plan attached to customer| B[Customer Balance] + +``` + +Customers can also [Stack Balances](/documentation/customers/balance-stacking) of the same feature from multiple plans (eg, an add-on plan), or different reset intervals (eg, monthly credits and one-time top-ups). + + +## Core Fields + +Each balance has the following key fields: + +| Field | Description | +|-------|-------------| +| `included_usage` | The amount granted by the plan, or a purchased quantity | +| `balance` | The remaining amount available | +| `usage` | The amount that has been consumed | + +When you retrieve a customer, their balances will be included in the response. + + +For the complete balance schema including reset configuration, overage settings, and breakdown details, see the [Get Customer API reference](/api-reference/customers/get-customer). + + + +```json +{ + "balances": { + "messages": { + "granted_balance": 1000, + "current_balance": 750, + "usage": 250, + "unlimited": false, + "reset": { + "interval": "month", + "resets_at": 1745193600000 + } + }, + "premium-support": { + "unlimited": true + } + } +} +``` + + +## Feature Types and Balances + +When you create a feature, you define its type. This affects how balances behave. + +### Consumable Features + +Features that are used up and can be replenished. Examples: credits, API requests, AI tokens. + +Consumable features support **reset intervals** - the balance resets to the granted amount on a regular schedule. + +Available reset intervals: +- `hour`, `day`, `week`, `month`, `quarter`, `semi_annual`, `year` +- `one_off` - the balance never resets (useful for one-time grants or top-ups) + +### Non-Consumable Features + +Features with persistent, continuous usage. Examples: seats, workspaces, storage. + +Non-consumable features don't reset. Instead, they support **proration** when quantities change mid-billing cycle. + +### Credit Systems + +A [credit system](/documentation/pricing/credits) lets multiple features draw from a single shared balance. + +When you check or track usage, you use the underlying feature ID (e.g., `premium_message`), but the balance is deducted from the credit system. + +When you track usage for a feature in a credit system, Autumn: +1. Looks up the credit cost for that feature that you defined +2. Multiplies the usage value by the credit cost +3. Deducts from the credit system balance + +For example, if you have a credit system with a credit cost of 2 credits per API request, and a customer uses 10 API requests, Autumn will deduct 20 credits from the balance. + + +## Positive and Negative Balances + +A balance can be positive or negative: + +- **Positive balance**: Customer has unused allowance remaining +- **Negative balance**: Customer has used more than their allowance (only possible if [overage](/documentation/pricing/plan-features#priced-features) is enabled) + + +Features can only have a negative balance if they have a usage-based price that allows overage. Otherwise, tracking stops when balance reaches 0. + + diff --git a/apps/docs/mintlify/documentation/customers/subscriptions/accepting-payments.mdx b/apps/docs/mintlify/documentation/customers/subscriptions/accepting-payments.mdx new file mode 100644 index 000000000..7f6439f7e --- /dev/null +++ b/apps/docs/mintlify/documentation/customers/subscriptions/accepting-payments.mdx @@ -0,0 +1,168 @@ +--- +title: "Accepting Payments" +description: "How to handle the Stripe payment flow with Autumn" +--- + +Accepting payments is a two-step process: + +1. **`checkout`** - Gets checkout information (either a Stripe Checkout URL or purchase confirmation data) +2. **`attach`** - Enables the product and charges a saved payment method + +```mermaid +graph TD + A(("checkout")) -->|"url"| B["Stripe Checkout"] + A -->|"preview"| C["Display preview info"] + B --> D["Payment complete"] + D --> E["Plan enabled"] + C --> F["User confirms"] + F --> G(("attach")) + G --> D +``` + +## Checkout + +Call `checkout` when a customer wants to purchase a product. If no payment method is on file, a Stripe Checkout URL is returned. Otherwise, preview data (prices, proration info) is returned for the customer to confirm. + + + +```tsx React +import { useCustomer, CheckoutDialog } from "autumn-js/react"; + +const { checkout } = useCustomer(); + +