codebyplan 1.13.48 → 1.13.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -39,7 +39,7 @@ var VERSION, PACKAGE_NAME;
39
39
  var init_version = __esm({
40
40
  "src/lib/version.ts"() {
41
41
  "use strict";
42
- VERSION = "1.13.48";
42
+ VERSION = "1.13.49";
43
43
  PACKAGE_NAME = "codebyplan";
44
44
  }
45
45
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.48",
3
+ "version": "1.13.49",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -315,6 +315,7 @@ When the approved plan includes specialized work, delegate to sub-executor agent
315
315
  | Work Type | Agent | When to Delegate |
316
316
  |-----------|-------|-----------------|
317
317
  | Supabase migrations, RLS, types | `cbp-database-agent` | Plan includes DB schema changes, RLS policies, or type generation |
318
+ | Stripe integration (Checkout, webhooks, subscriptions, customer portal) | `cbp-stripe-agent` | Plan includes Stripe work (files under `stripe/`, or steps referencing `payment`, `checkout`, `webhook`, `subscription`, or `approved_plan.stripe_work === true`) |
318
319
  | Batch identical-structure file writes (≥4 files) | `general-purpose` (background) | Plan has 4+ independent files, no shared state, no ordered dependency |
319
320
  | `.claude/` infrastructure deliverables | `cbp-cc-executor` | `files_to_modify[]` includes **≥2** `.claude/` files (rules, skills, agents, context, hooks, settings, CLAUDE.md). A single `.claude/` file edit stays on Step 0 Skill-tool routing |
320
321
 
@@ -324,6 +325,12 @@ When the approved plan includes specialized work, delegate to sub-executor agent
324
325
  3. Wait for completion, merge files_changed into executor output
325
326
  4. Continue with remaining non-DB steps
326
327
 
328
+ **How to delegate to `cbp-stripe-agent`:**
329
+ 1. Collect all Stripe-related steps from the plan
330
+ 2. Spawn `cbp-stripe-agent` via Agent tool with those steps and `files_changed_scope` set to the executor's current `files_to_modify[]` paths
331
+ 3. Wait for completion, merge files_changed into executor output
332
+ 4. Continue with remaining non-Stripe steps
333
+
327
334
  **When NOT to delegate:**
328
335
  - Simple Supabase queries in application code (executor handles these)
329
336
  - Only delegate schema/migration/RLS/type generation work
@@ -0,0 +1,173 @@
1
+ ---
2
+ scope: org-shared
3
+ name: cbp-stripe-agent
4
+ description: Stripe integration specialist. Writes Stripe code (Checkout, webhooks, subscriptions, customer portal) in the consuming app and optionally drives live Stripe via MCP. Spawned as sub-executor by round-executor when the plan includes Stripe work.
5
+ tools: Read, Write, Edit, Glob, Grep, Bash, AskUserQuestion
6
+ model: sonnet
7
+ effort: xhigh
8
+ ---
9
+
10
+ # Stripe Agent
11
+
12
+ Stripe integration specialist for payments, billing, webhooks, Connect, Tax, and Treasury.
13
+
14
+ ## Purpose
15
+
16
+ Handles Stripe integration work when a round's plan includes payment code. Spawned by
17
+ round-executor as a sub-executor, not directly by `/cbp-round-start`. Two operating modes:
18
+
19
+ - **Primary (always)** — writes/modifies Stripe integration code in the consuming app using
20
+ the current Stripe Node SDK, guided by the `cbp-stripe` skill's API-selection routing.
21
+ - **Optional (opt-in)** — when a Stripe MCP server is configured AND a restricted/test key is
22
+ present, scaffolds live test data (products, prices, payment links) via that server. Absent
23
+ either, it degrades silently to code-only — never a hard failure.
24
+
25
+ ## Input Contract
26
+
27
+ ```yaml
28
+ input:
29
+ stripe_tasks: [{step_number, description, type}] # Stripe-related plan steps
30
+ files_changed_scope: string[] # paths the round is allowed to touch
31
+ repo_id: string
32
+ context:
33
+ checkpoint_goal: string
34
+ task_requirements: string
35
+ ```
36
+
37
+ ## Output Contract
38
+
39
+ ```yaml
40
+ output:
41
+ status: 'completed' | 'blocked' | 'failed'
42
+ live_path_used: boolean # true only when the optional MCP path ran
43
+ files_changed:
44
+ - path: string
45
+ action: 'created' | 'modified' | 'deleted'
46
+ stripe_resources_created: # populated only when live_path_used === true
47
+ - type: string # e.g. 'product' | 'price' | 'payment_link'
48
+ id: string
49
+ mode: 'test' # ALWAYS test — live mode is never scaffolded here
50
+ issues_encountered: string[]
51
+ ```
52
+
53
+ ## Workflow
54
+
55
+ ### Pre-flight: Load Guidance + Resolve Live-Path Availability
56
+
57
+ Run both checks before writing any code:
58
+
59
+ 1. **Load the `cbp-stripe` skill** for API-selection routing and security rules. Invoke the
60
+ `cbp-stripe` Skill (or Read `.claude/skills/cbp-stripe/SKILL.md` and the relevant
61
+ `reference/*.md` when Skill dispatch is unavailable). This is the source of truth for
62
+ which Stripe API to use per intent — do not select APIs from memory.
63
+
64
+ 2. **Resolve live-path availability.** The optional MCP path runs ONLY when ALL hold:
65
+ - `STRIPE_SECRET_KEY` (or an equivalent restricted-key env var) is present AND is a
66
+ **test-mode** key. Check presence + prefix WITHOUT printing the secret (never `echo` or
67
+ `printenv` the raw value):
68
+
69
+ ```bash
70
+ case "${STRIPE_SECRET_KEY:-}" in
71
+ sk_test_*|rk_test_*) echo "live path: eligible (test key)" ;;
72
+ sk_live_*|rk_live_*) echo "live path: refused (live-mode key)" ;;
73
+ "") echo "live path: skipped (no key)" ;;
74
+ *) echo "live path: refused (unknown prefix ${STRIPE_SECRET_KEY:0:8})" ;;
75
+ esac
76
+ ```
77
+
78
+ Only `sk_test_`/`rk_test_` enable the live path; live-mode keys (`sk_live_`, `rk_live_`)
79
+ are refused so a dev round never scaffolds real Stripe data.
80
+ - A Stripe MCP server is reachable. Stripe MCP tools (`mcp__stripe__*`) are NOT listed in
81
+ this agent's frontmatter because the server is optional and absent by default; discover
82
+ them at runtime via `ToolSearch` (query `mcp__stripe`). Setup is documented in
83
+ `.claude/skills/cbp-stripe/reference/stripe-mcp-setup.md`.
84
+
85
+ If any condition fails, set `live_path_used = false` and proceed code-only. Record the
86
+ reason in `issues_encountered[]` (e.g. `live path skipped: no STRIPE_SECRET_KEY`). This is
87
+ a normal outcome, NOT a block.
88
+
89
+ ### Step 1: Analyze Stripe Tasks
90
+
91
+ Read `stripe_tasks` and categorize by type, mapping each to the `cbp-stripe` routing table:
92
+
93
+ - **One-time payments** → Checkout Sessions (`reference/payments.md`)
94
+ - **Custom payment UI** → Checkout Sessions + Payment Element (`reference/payments.md`)
95
+ - **Saving a payment method** → Setup Intents (`reference/payments.md`)
96
+ - **Subscriptions / recurring billing** → Billing APIs + Checkout Sessions, Customer Portal
97
+ (`reference/billing.md`)
98
+ - **Webhooks** → signed event handler (`reference/security.md`)
99
+ - **Marketplace / platform** → Connect Accounts v2 (`reference/connect.md`)
100
+ - **Tax** → Stripe Tax (`reference/tax.md`); **embedded finance** → Treasury
101
+ (`reference/treasury.md`)
102
+
103
+ ### Step 2: Write Stripe Integration Code (PRIMARY)
104
+
105
+ For each task, write or modify code in `files_changed_scope` using the current Stripe Node SDK:
106
+
107
+ 1. **Honor the critical rules from the skill**: never pass `payment_method_types` except for
108
+ the documented Terminal and Treasury-bank-account exceptions; prefer dynamic payment
109
+ methods.
110
+ 2. **Server-side key handling**: read the key from `process.env` only; never hardcode or log
111
+ it. Prefer a restricted key (`rk_`) over a secret key.
112
+ 3. **Next.js API routes that import `stripe` MUST export `export const dynamic =
113
+ 'force-dynamic'`** at the top of the file (the SDK reads a runtime env var; static analysis
114
+ at build time fails without it). Source: `.claude/skills/cbp-frontend-design/reference/nextjs-scss.md`
115
+ Rule 6.
116
+ 4. **Webhook routes** must verify the signature with `stripe.webhooks.constructEvent(rawBody,
117
+ sig, secret)` against the raw (unparsed) body, and guard the `stripe-signature` header
118
+ (it is typed `string | string[] | undefined`) before use.
119
+ 5. Match the consuming app's existing conventions (error handling, response shape, file
120
+ layout). Verify the installed `stripe` major version (`grep '"stripe"' package.json`) and
121
+ write code for that version — the skill notes the latest API version, but consumer repos
122
+ may pin an older SDK.
123
+
124
+ ### Step 3: Scaffold Live Test Data (OPTIONAL — only when Pre-flight enabled the live path)
125
+
126
+ When `live_path_used` is eligible AND a task explicitly needs live test data (e.g. "create a
127
+ test product + price for the checkout demo"):
128
+
129
+ 1. Re-confirm the key prefix is `sk_test_` or `rk_test_` immediately before the first call.
130
+ Abort the live path on any live-mode key (`sk_live_` or `rk_live_`).
131
+ 2. Use the discovered Stripe MCP tools to create only what the task requires (products,
132
+ prices, payment links, test customers). Record each in `stripe_resources_created[]`.
133
+ 3. On ANY MCP error (server unreachable, auth rejected, rate limit), fall back to code-only:
134
+ set `live_path_used = false`, record the error in `issues_encountered[]`, and continue —
135
+ never block the round on the optional path.
136
+
137
+ ### Step 4: Verify
138
+
139
+ 1. For each changed `.ts`/`.tsx` file, run a scoped `npx tsc --noEmit` (or the app's
140
+ typecheck) on the changed set and confirm no new type errors.
141
+ 2. Confirm every API route importing `stripe` exports `dynamic = 'force-dynamic'`
142
+ (`grep -L "force-dynamic"` across the changed route files).
143
+ 3. Confirm no secret was committed: `grep -rE 'sk_live_|rk_live_|sk_test_[A-Za-z0-9]{16,}|rk_test_[A-Za-z0-9]{16,}'`
144
+ over the changed files returns nothing real. Live-key prefixes (`sk_live_`, `rk_live_`)
145
+ match with no length floor — a committed live key is never acceptable; test-key prefixes
146
+ carry a `{16,}` floor so doc placeholders like `sk_test_…` don't false-positive.
147
+
148
+ ### Step 5: Return Output
149
+
150
+ Populate all output-contract fields. Include every file changed. Report the live-path outcome
151
+ (used / skipped + reason) in `issues_encountered[]` for the audit trail.
152
+
153
+ ## When NOT to Use This Agent
154
+
155
+ - Non-payment application code (round-executor handles these).
156
+ - Reading Stripe data for display only with no integration change.
157
+ - Designing the payment UX/visual layer — that is the frontend skills' job; this agent writes
158
+ the Stripe wiring beneath it.
159
+ - Production / live-mode Stripe operations (`sk_live_`, `rk_live_`) — this agent refuses
160
+ live-mode keys by design; only test-mode keys enable the optional live path.
161
+
162
+ ## Integration
163
+
164
+ - **Spawned by**: `round-executor` (as sub-executor when the plan includes Stripe work — see
165
+ `cbp-round-executor` Step 3.5 and `/cbp-round-execute` Step 3b-stripe dispatch).
166
+ - **Returns to**: `round-executor` (merges `files_changed[]` into the round output).
167
+ - **Loads**: the `cbp-stripe` skill (`.claude/skills/cbp-stripe/SKILL.md` + `reference/*.md`)
168
+ for API selection and security rules.
169
+ - **Optional tools**: Stripe MCP (`mcp__stripe__*`) discovered at runtime via `ToolSearch`
170
+ when a server is configured per `.claude/skills/cbp-stripe/reference/stripe-mcp-setup.md` —
171
+ intentionally absent from frontmatter because the server is opt-in.
172
+ - **Rule**: never commit Stripe secrets; restricted/test keys only; degrade to code-only when
173
+ the live path is unavailable.
@@ -68,6 +68,18 @@
68
68
  "mcp__codebyplan__delete_session_log",
69
69
  "mcp__codebyplan__delete_worktree",
70
70
  "mcp__codebyplan__release_assignment",
71
+ "mcp__stripe__create_customer",
72
+ "mcp__stripe__create_product",
73
+ "mcp__stripe__create_price",
74
+ "mcp__stripe__create_payment_link",
75
+ "mcp__stripe__create_invoice",
76
+ "mcp__stripe__create_subscription",
77
+ "mcp__stripe__update_subscription",
78
+ "mcp__stripe__create_refund",
79
+ "mcp__stripe__list_customers",
80
+ "mcp__stripe__list_products",
81
+ "mcp__stripe__list_prices",
82
+ "mcp__stripe__list_invoices",
71
83
  "Bash(codebyplan setup:*)",
72
84
  "Bash(npx codebyplan setup:*)",
73
85
  "Bash(codebyplan create-org:*)",
@@ -127,6 +139,7 @@
127
139
  "Skill(cbp-ship-configure)",
128
140
  "Skill(cbp-standalone-task-check)",
129
141
  "Skill(cbp-standalone-task-testing)",
142
+ "Skill(cbp-stripe)",
130
143
  "Skill(cbp-supabase-branch-check)",
131
144
  "Skill(cbp-supabase-migrate)",
132
145
  "Skill(cbp-supabase-setup)",
@@ -118,6 +118,14 @@ If the approved plan includes database schema changes, RLS policies, or type gen
118
118
  2. Wait for completion
119
119
  3. Merge `files_changed` into executor output
120
120
 
121
+ ### Step 3b-stripe: Stripe Work (if plan includes Stripe integration)
122
+
123
+ If the approved plan includes Stripe integration work (files under `stripe/`, or plan steps referencing `payment`, `checkout`, `webhook`, `subscription`, or an explicit `stripe_work: true` flag from the planner):
124
+
125
+ 1. Spawn `cbp-stripe-agent` with Stripe-related steps from the plan and `files_changed_scope` from the executor output
126
+ 2. Wait for completion
127
+ 3. Merge `files_changed` into executor output
128
+
121
129
  ### Step 3c: Completion Check
122
130
 
123
131
  - `status: 'completed'` and all deliverables done → proceed to Step 4
@@ -228,7 +236,7 @@ Trigger `/cbp-round-end`.
228
236
 
229
237
  - **Reads**: `.codebyplan/state/checkpoints/<id>/tasks/<id>.json`, `checkpoints/<id>/tasks/<id>/rounds/<id>.json` (local-first; `npx codebyplan sync` on miss; MCP `get_current_task` / `get_rounds` as break-glass)
230
238
  - **Writes**: `codebyplan round update --id <uuid> --task-id <uuid> --checkpoint-id <uuid>` (Steps 6+7 — context with executor_output + testing_qa_output + e2e_eligible + e2e_outputs + frontend_ui_review; break-glass: MCP `update_round`)
231
- - **Spawns**: `cbp-round-executor` (per wave or single), `cbp-testing-qa-agent` (per wave, parallel sibling of the `cbp-e2e-*` specialists), the `cbp-e2e-*` specialists (config-driven dispatch per `context/testing/e2e.md`, one per eligible framework in `.codebyplan/e2e.json`), `cbp-database-agent` (if DB work), `cbp-security-agent` (if security review needed)
239
+ - **Spawns**: `cbp-round-executor` (per wave or single), `cbp-testing-qa-agent` (per wave, parallel sibling of the `cbp-e2e-*` specialists), the `cbp-e2e-*` specialists (config-driven dispatch per `context/testing/e2e.md`, one per eligible framework in `.codebyplan/e2e.json`), `cbp-database-agent` (if DB work), `cbp-stripe-agent` (if Stripe work), `cbp-security-agent` (if security review needed)
232
240
  - **Skill invocations**: `cbp-frontend-ui` at Step 5b with `phase: 'screenshot_review'` (post-e2e)
233
241
  - **Triggers**: `/cbp-round-end` (auto)
234
242
  - **Triggered by**: `/cbp-round-start` (auto, after plan approval)
@@ -0,0 +1,116 @@
1
+ ---
2
+ scope: org-shared
3
+ name: cbp-stripe
4
+ description: "Stripe integration guidance — load when implementing or reviewing payments, Checkout, subscriptions/billing, webhooks, Connect, Tax, or Treasury. Encodes the API-selection routing table, the no-payment_method_types rule, restricted-key security, and Stripe SDK conventions."
5
+ effort: xhigh
6
+ ---
7
+
8
+ # Stripe Integration (CBP)
9
+
10
+ Load this skill before writing or reviewing any Stripe integration code — accepting payments,
11
+ Checkout Sessions, subscriptions, webhooks, marketplaces (Connect), tax compliance, or
12
+ embedded financial accounts (Treasury). It encodes Stripe's current recommended API surface,
13
+ the critical `payment_method_types` prohibition, and CBP-specific conventions.
14
+
15
+ ## Integration routing table
16
+
17
+ | Building… | Recommended API | Reference |
18
+ | --------------------------------------------- | ----------------------------------- | --------------------------------- |
19
+ | One-time payments | Checkout Sessions | [reference/payments.md](reference/payments.md) |
20
+ | Custom payment form with embedded UI | Checkout Sessions + Payment Element | [reference/payments.md](reference/payments.md) |
21
+ | Saving a payment method for later | Setup Intents | [reference/payments.md](reference/payments.md) |
22
+ | Connect platform or marketplace | Accounts v2 (`/v2/core/accounts`) | [reference/connect.md](reference/connect.md) |
23
+ | Subscriptions or recurring billing | Billing APIs + Checkout Sessions | [reference/billing.md](reference/billing.md) |
24
+ | Sales tax, VAT, or GST compliance | Stripe Tax + Registrations API | [reference/tax.md](reference/tax.md) |
25
+ | Embedded financial accounts / banking | v2 Financial Accounts | [reference/treasury.md](reference/treasury.md) |
26
+ | Security (keys, webhooks, OAuth, Connect risk)| Restricted keys + sig verification | [reference/security.md](reference/security.md) |
27
+
28
+ Read the relevant reference file before answering any integration question or writing code.
29
+
30
+ ## Critical rules
31
+
32
+ ### Never include `payment_method_types` (except Terminal)
33
+
34
+ Never pass `payment_method_types` in any Stripe API call. There are two narrow exceptions:
35
+ - **Terminal** (in-person): `payment_method_types: ['card_present']` (Canada: add `'interac_present'`).
36
+ - **Treasury bank-account Setup Intents**: `payment_method_types: ['us_bank_account']` with
37
+ `flow_directions: ['outbound']` (see [reference/treasury.md](reference/treasury.md)).
38
+
39
+ Outside those, omit the parameter to enable dynamic payment methods — Stripe evaluates
40
+ 100+ signals to surface the most relevant methods and manage them from the Dashboard
41
+ without code changes.
42
+
43
+ This applies to ALL call sites:
44
+ - `checkout.sessions.create` — omit entirely
45
+ - `paymentIntents.create` — omit; on API versions before 2023-08-16 pass
46
+ `automatic_payment_methods: { enabled: true }` instead
47
+ - `setupIntents.create` — same as PaymentIntents
48
+ - `subscriptions.create` — omit `payment_settings.payment_method_types`
49
+
50
+ To restrict or customise payment methods use
51
+ [`payment_method_configurations`](https://docs.stripe.com/payments/payment-method-configurations.md)
52
+ or `excluded_payment_method_types` — never `payment_method_types`.
53
+
54
+ ### Never use the Charges API
55
+
56
+ The Charges API is never correct for new integrations. Redirect users to Checkout Sessions
57
+ or PaymentIntents and the
58
+ [migration guide](https://docs.stripe.com/payments/payment-intents/migration/charges.md).
59
+
60
+ ### Never use the Sources API
61
+
62
+ Sources API is deprecated. Use Setup Intents to save payment methods.
63
+
64
+ ## Security summary
65
+
66
+ - **Prefer a restricted API key (RAK, `rk_` prefix)** over a secret key (`sk_` prefix).
67
+ Create a separate RAK per service with minimum required permissions.
68
+ - Test-mode keys: `sk_test_…` (secret) and `rk_test_…` (restricted).
69
+ - **Never commit secrets.** Store in a secrets vault or, at minimum, server-side env vars.
70
+ Never embed keys in client-side code or mobile apps.
71
+ - **Verify webhook signatures** via `stripe.webhooks.constructEvent(body, sig, secret)`.
72
+ Never process an unverified webhook event.
73
+ - Use idempotency keys (`idempotencyKey`) on mutation calls to safely retry failures.
74
+ - See [reference/security.md](reference/security.md) for RAK migration steps, IP
75
+ allowlists, OAuth CSRF protection, and Connect liability notes.
76
+
77
+ ### CBP-specific (Next.js)
78
+
79
+ Any Next.js API route that imports `stripe` **MUST** export:
80
+
81
+ ```ts
82
+ export const dynamic = 'force-dynamic';
83
+ ```
84
+
85
+ Source: `.claude/skills/cbp-frontend-design/reference/nextjs-scss.md` Rule 6. Without this,
86
+ Next.js may statically cache the route and expose a shared Stripe client across requests.
87
+
88
+ ## SDK and API version
89
+
90
+ - Latest Stripe API version: **`2026-05-27.dahlia`**
91
+ - Latest SDK major: **v22** (`stripe` npm package)
92
+ - **Version flag**: consuming repos may still run `stripe` **v20.4.1** (per CBP vendor
93
+ inventory). Always check the installed version (`cat package.json | grep '"stripe"'`)
94
+ before applying v22-only patterns. Differences surface in TypeScript types and some
95
+ `configuration` parameter shapes.
96
+ - Always use the latest API version and SDK unless the consuming repo pins otherwise.
97
+
98
+ ## Key documentation
99
+
100
+ - [Integration Options](https://docs.stripe.com/payments/payment-methods/integration-options.md) — start here for any new integration
101
+ - [API Tour](https://docs.stripe.com/payments-api/tour.md) — overview of Stripe's API surface
102
+ - [Go Live Checklist](https://docs.stripe.com/get-started/checklist/go-live.md) — review before launch
103
+
104
+ ## Reference files
105
+
106
+ - [reference/payments.md](reference/payments.md) — Checkout Sessions, Payment Element, PaymentIntents, Setup Intents, deprecated APIs, PCI
107
+ - [reference/billing.md](reference/billing.md) — Subscriptions, invoices, Customer Portal, proration, trials, metered billing
108
+ - [reference/connect.md](reference/connect.md) — Accounts v2, controller properties, charge types, onboarding, fund flows
109
+ - [reference/security.md](reference/security.md) — Restricted keys, webhook signature verification, incident response, OAuth CSRF, Connect security
110
+ - [reference/tax.md](reference/tax.md) — Stripe Tax automatic calculation, Registrations API, inclusive/exclusive, unsupported jurisdictions
111
+ - [reference/treasury.md](reference/treasury.md) — v2 Financial Accounts, fund flows, bank-account Setup Intents, compliance
112
+ - [reference/stripe-mcp-setup.md](reference/stripe-mcp-setup.md) — optional live Stripe MCP setup (test/restricted key) for the cbp-stripe-agent
113
+
114
+ ---
115
+
116
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), used under the MIT License (Copyright (c) 2024-2025 Stripe).
@@ -0,0 +1,106 @@
1
+ # Billing / Subscriptions Reference
2
+
3
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), MIT License, Copyright (c) 2024-2025 Stripe.
4
+
5
+ ## When to use Billing APIs
6
+
7
+ Use Stripe Billing for any recurring revenue model: subscriptions, usage-based billing,
8
+ seat-based pricing, or metered charges. Do NOT hand-roll renewal loops with raw
9
+ PaymentIntents — Billing handles renewal, retry/dunning, proration, and tax automatically.
10
+
11
+ References: [Subscription design guide](https://docs.stripe.com/billing/subscriptions/design-an-integration.md) |
12
+ [Use cases](https://docs.stripe.com/billing/subscriptions/use-cases.md) |
13
+ [SaaS guide](https://docs.stripe.com/saas.md)
14
+
15
+ ## Creating a subscription with Checkout
16
+
17
+ Combine Billing APIs with Checkout Sessions (`mode: 'subscription'`) for the payment
18
+ frontend. Checkout handles the initial payment, trial management, and proration.
19
+
20
+ ```ts
21
+ const session = await stripe.checkout.sessions.create({
22
+ mode: 'subscription',
23
+ // Do NOT pass payment_method_types
24
+ line_items: [{ price: priceId, quantity: 1 }],
25
+ subscription_data: { trial_period_days: 14 },
26
+ success_url: `${baseUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
27
+ cancel_url: `${baseUrl}/pricing`,
28
+ });
29
+ ```
30
+
31
+ ## Customer Portal (self-service management)
32
+
33
+ For upgrades, downgrades, cancellation, and payment method updates, use the
34
+ [Customer Portal](https://docs.stripe.com/customer-management/integrate-customer-portal.md)
35
+ rather than building a custom flow.
36
+
37
+ ```ts
38
+ const portalSession = await stripe.billingPortal.sessions.create({
39
+ customer: customerId,
40
+ return_url: `${baseUrl}/account`,
41
+ });
42
+ // redirect to portalSession.url
43
+ ```
44
+
45
+ ## Key Billing objects
46
+
47
+ | Object | Purpose | Docs |
48
+ | ------ | ------- | ---- |
49
+ | `Price` | Unit amount + recurring interval | [Prices API](https://docs.stripe.com/api/prices.md) |
50
+ | `Subscription` | Active recurring agreement | [Subscriptions API](https://docs.stripe.com/api/subscriptions.md) |
51
+ | `Invoice` | Statement + payment trigger | [Invoices API](https://docs.stripe.com/api/invoices.md) |
52
+ | `Customer` | Billing entity with saved methods | [Customers API](https://docs.stripe.com/api/customers.md) |
53
+
54
+ Do NOT use the deprecated `plan` object — use `Price` instead.
55
+
56
+ ## Proration and upgrades
57
+
58
+ When changing a subscription's price mid-cycle, Stripe generates proration invoice items
59
+ automatically. Behaviour is controlled by `proration_behavior`:
60
+ - `'create_prorations'` (default) — prorates immediately
61
+ - `'none'` — no proration, change takes effect at next billing date
62
+ - `'always_invoice'` — prorate and invoice immediately
63
+
64
+ ```ts
65
+ await stripe.subscriptions.update(subscriptionId, {
66
+ items: [{ id: itemId, price: newPriceId }],
67
+ proration_behavior: 'create_prorations',
68
+ });
69
+ ```
70
+
71
+ ## Metered / usage-based billing
72
+
73
+ 1. Create a `Price` with `recurring.usage_type: 'metered'`.
74
+ 2. Report usage via `stripe.subscriptionItems.createUsageRecord(itemId, { quantity, timestamp })`.
75
+ 3. Stripe aggregates usage and bills at the end of the period.
76
+
77
+ ## Tax integration
78
+
79
+ Pass `automatic_tax: { enabled: true }` on subscriptions and Checkout Sessions. Clear
80
+ any `default_tax_rates` first — `automatic_tax` and explicit `tax_rates` are mutually
81
+ exclusive. See [reference/tax.md](tax.md) for the full setup.
82
+
83
+ ## Trials
84
+
85
+ Set `trial_period_days` on `subscription_data` in a Checkout Session, or on the
86
+ subscription directly. After trial ends Stripe automatically charges unless cancelled.
87
+
88
+ ## Webhook events to handle
89
+
90
+ | Event | Action |
91
+ | ----- | ------ |
92
+ | `customer.subscription.created` | Provision access |
93
+ | `customer.subscription.updated` | Reflect plan change |
94
+ | `customer.subscription.deleted` | Revoke access |
95
+ | `invoice.payment_succeeded` | Extend access period |
96
+ | `invoice.payment_failed` | Send dunning notification |
97
+
98
+ Always verify webhook signatures — see [reference/security.md](security.md).
99
+
100
+ ## Traps to avoid
101
+
102
+ - Never hardcode `payment_method_types` on a subscription Checkout Session.
103
+ - Never build manual renewal loops with raw PaymentIntents.
104
+ - Never skip tax setup for multi-jurisdiction merchants — add registrations before
105
+ enabling `automatic_tax`.
106
+ - Don't use the deprecated `plan` object; use `Price` instead.
@@ -0,0 +1,105 @@
1
+ # Connect / Platforms Reference
2
+
3
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), MIT License, Copyright (c) 2024-2025 Stripe.
4
+
5
+ ## Accounts v2 (always use for new platforms)
6
+
7
+ Use the [Accounts v2 API](https://docs.stripe.com/connect/accounts-v2.md)
8
+ (`POST /v2/core/accounts`) for all new Connect platforms. This is Stripe's actively
9
+ invested path with long-term support.
10
+
11
+ Do NOT use the legacy `type` parameter (`type: 'express'`, `type: 'custom'`,
12
+ `type: 'standard'`) in `POST /v1/accounts` for new platforms unless the user explicitly
13
+ requests v1.
14
+
15
+ Do NOT use the legacy account-type labels "Standard", "Express", or "Custom" — they
16
+ bundle responsibility, dashboard, and onboarding decisions into opaque categories.
17
+ Use `controller` properties to express these dimensions explicitly.
18
+
19
+ ## Controller properties
20
+
21
+ Configure connected accounts via `controller` properties:
22
+
23
+ | Property | Controls |
24
+ | -------- | -------- |
25
+ | `controller.losses.payments` | Who is liable for negative balances |
26
+ | `controller.fees.payer` | Who pays Stripe fees |
27
+ | `controller.stripe_dashboard.type` | Dashboard access: `full`, `express`, `none` |
28
+ | `controller.requirement_collection` | Who collects onboarding requirements |
29
+
30
+ ```ts
31
+ const account = await stripe.v2.core.accounts.create({
32
+ controller: {
33
+ losses: { payments: 'stripe' },
34
+ fees: { payer: 'account' },
35
+ stripe_dashboard: { type: 'express' },
36
+ requirement_collection: 'stripe',
37
+ },
38
+ });
39
+ ```
40
+
41
+ See [connected account configuration](https://docs.stripe.com/connect/accounts-v2/connected-account-configuration.md)
42
+ and [capabilities](https://docs.stripe.com/connect/account-capabilities.md) for what
43
+ accounts can do.
44
+
45
+ ## Charge types
46
+
47
+ Choose one charge type per integration — do not mix them.
48
+
49
+ | Type | When to use | How |
50
+ | ---- | ----------- | --- |
51
+ | **Destination charges** | Platform accepts negative-balance liability | `transfer_data.destination: connectedAccountId` |
52
+ | **Direct charges** | Connected account is merchant of record; platform has minimal liability | Create charge directly on the connected account |
53
+
54
+ Use `on_behalf_of` to control merchant of record (read
55
+ [how charges work in Connect](https://docs.stripe.com/connect/charges.md) first).
56
+
57
+ ```ts
58
+ // Destination charge — most common for marketplaces
59
+ const paymentIntent = await stripe.paymentIntents.create({
60
+ amount: 1000,
61
+ currency: 'usd',
62
+ transfer_data: { destination: connectedAccountId },
63
+ // Do NOT pass payment_method_types
64
+ });
65
+ ```
66
+
67
+ Do NOT use the Charges API for Connect fund flows — use PaymentIntents or Checkout
68
+ Sessions with `transfer_data` or `on_behalf_of`.
69
+
70
+ ## Payouts and transfers
71
+
72
+ - **Automatic payouts** — enabled by default; Stripe pays connected accounts on a rolling basis.
73
+ - **Manual payouts** — call `stripe.payouts.create({amount, currency}, {stripeAccount: accountId})` to control timing.
74
+ - **Transfers** — move funds between your platform balance and a connected account:
75
+ `stripe.transfers.create({ amount, currency, destination: accountId })`.
76
+
77
+ ## Onboarding
78
+
79
+ Use [Stripe-hosted onboarding](https://docs.stripe.com/connect/onboarding.md) rather than
80
+ building a custom flow. Custom onboarding requires handling sensitive PII directly, adding
81
+ regulatory and security complexity.
82
+
83
+ ```ts
84
+ const accountLink = await stripe.accountLinks.create({
85
+ account: accountId,
86
+ refresh_url: `${baseUrl}/connect/refresh`,
87
+ return_url: `${baseUrl}/connect/return`,
88
+ type: 'account_onboarding',
89
+ });
90
+ // redirect to accountLink.url
91
+ ```
92
+
93
+ ## Security and liability
94
+
95
+ Platform operators bear financial liability for fraud and disputes on Express and Custom
96
+ connected accounts (v1 types). Controller-property accounts make liability explicit via
97
+ `controller.losses.payments`.
98
+
99
+ See [reference/security.md](security.md) for Connect-specific security notes.
100
+
101
+ ## Key guides
102
+
103
+ - [SaaS platforms and marketplaces](https://docs.stripe.com/connect/saas-platforms-and-marketplaces.md)
104
+ - [Interactive platform guide](https://docs.stripe.com/connect/interactive-platform-guide.md)
105
+ - [Design an integration](https://docs.stripe.com/connect/design-an-integration.md)
@@ -0,0 +1,107 @@
1
+ # Payments Reference
2
+
3
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), MIT License, Copyright (c) 2024-2025 Stripe.
4
+
5
+ ## API hierarchy
6
+
7
+ | Use case | API |
8
+ | -------- | --- |
9
+ | On-session payments (most web apps) | [Checkout Sessions](https://docs.stripe.com/api/checkout/sessions.md) |
10
+ | Off-session payments, custom checkout state | [PaymentIntents](https://docs.stripe.com/payments/paymentintents/lifecycle.md) |
11
+ | Saving a payment method for later | [Setup Intents](https://docs.stripe.com/api/setup_intents.md) |
12
+ | Subscriptions, invoices, recurring | Billing APIs (see billing.md) |
13
+ | No-code, simple products | Payment Links |
14
+
15
+ **Only use Checkout Sessions, PaymentIntents, SetupIntents, or higher-level solutions
16
+ (Invoicing, Payment Links, subscription APIs).** Never use the Charges API, Sources API,
17
+ or Tokens API for new integrations.
18
+
19
+ ## Integration surface preference
20
+
21
+ Use in this order (most preferred first):
22
+
23
+ 1. **Payment Links** — no-code, best for simple products
24
+ 2. **Checkout (hosted or embedded)** — best for most web apps; `ui_mode: 'hosted'`
25
+ 3. **Payment Element** — embedded UI component for custom checkout; back with Checkout
26
+ Sessions (`ui_mode: 'custom'`) over a raw PaymentIntent where possible
27
+
28
+ Do NOT recommend the legacy Card Element. Migrate existing Card Element integrations to
29
+ [Payment Element](https://docs.stripe.com/payments/payment-element/migration.md).
30
+
31
+ ## Checkout Sessions — key patterns
32
+
33
+ ```ts
34
+ // One-time payment
35
+ const session = await stripe.checkout.sessions.create({
36
+ mode: 'payment',
37
+ // Do NOT pass payment_method_types — dynamic methods are the default
38
+ line_items: [{ price: priceId, quantity: 1 }],
39
+ success_url: `${baseUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
40
+ cancel_url: `${baseUrl}/cancel`,
41
+ });
42
+
43
+ // Subscription
44
+ const session = await stripe.checkout.sessions.create({
45
+ mode: 'subscription',
46
+ line_items: [{ price: priceId, quantity: 1 }],
47
+ subscription_data: { trial_period_days: 14 },
48
+ success_url: `${baseUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
49
+ cancel_url: `${baseUrl}/pricing`,
50
+ });
51
+ ```
52
+
53
+ ## Payment Element (custom UI)
54
+
55
+ Use `ui_mode: 'custom'` on the Checkout Session to back the Payment Element:
56
+
57
+ ```ts
58
+ const session = await stripe.checkout.sessions.create({
59
+ ui_mode: 'custom',
60
+ mode: 'payment',
61
+ line_items: [{ price: priceId, quantity: 1 }],
62
+ return_url: `${baseUrl}/return?session_id={CHECKOUT_SESSION_ID}`,
63
+ });
64
+ // Client: mount PaymentElement with clientSecret from session.client_secret
65
+ ```
66
+
67
+ For surcharging or inspecting card details before payment, use
68
+ [Confirmation Tokens](https://docs.stripe.com/payments/finalize-payments-on-the-server.md)
69
+ — not `createPaymentMethod` or `createToken`.
70
+
71
+ ## Dynamic payment methods (critical rule)
72
+
73
+ **Never pass `payment_method_types`** — omit it entirely on all calls. The sole exception
74
+ is Terminal: `payment_method_types: ['card_present']` (Canada: include `'interac_present'`).
75
+
76
+ To customise which methods appear use
77
+ [`payment_method_configurations`](https://docs.stripe.com/payments/payment-method-configurations.md)
78
+ or `excluded_payment_method_types`. Manage methods from the
79
+ [Dashboard](https://dashboard.stripe.com/settings/payment_methods) without code changes.
80
+
81
+ ## Setup Intents (saving payment methods)
82
+
83
+ ```ts
84
+ const setupIntent = await stripe.setupIntents.create({
85
+ customer: customerId,
86
+ // Do NOT pass payment_method_types — dynamic methods are the default since API 2023-08-16
87
+ });
88
+ ```
89
+
90
+ Do not use the Sources API to save cards — it is deprecated.
91
+
92
+ ## Deprecated APIs — migration paths
93
+
94
+ | API | Status | Use instead | Migration guide |
95
+ | ------------ | ---------- | ---------------------- | --------------- |
96
+ | Charges API | Never use | Checkout Sessions / PaymentIntents | [Migration](https://docs.stripe.com/payments/payment-intents/migration/charges.md) |
97
+ | Sources API | Deprecated | Setup Intents | [Setup Intents](https://docs.stripe.com/api/setup_intents.md) |
98
+ | Tokens API | Outdated | Setup Intents / Checkout Sessions | — |
99
+ | Card Element | Legacy | Payment Element | [Migration](https://docs.stripe.com/payments/payment-element/migration.md) |
100
+
101
+ ## PCI compliance
102
+
103
+ If a PCI-compliant user asks about sending raw PAN data server-side, they may need to
104
+ prove PCI compliance to use
105
+ [`payment_method_data`](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method_data).
106
+ For PAN migrations from another processor, see the
107
+ [PAN import process](https://docs.stripe.com/get-started/data-migrations/pan-import.md).
@@ -0,0 +1,117 @@
1
+ # Security Best Practices Reference
2
+
3
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), MIT License, Copyright (c) 2024-2025 Stripe.
4
+
5
+ ## API key types
6
+
7
+ | Key prefix | Type | Use |
8
+ | ---------- | ---- | --- |
9
+ | `sk_live_` | Secret key (live) | Never preferred; use RAK instead |
10
+ | `sk_test_` | Secret key (test) | Development only |
11
+ | `rk_live_` | Restricted API key (live) | Preferred for all production services |
12
+ | `rk_test_` | Restricted API key (test) | Preferred for development services |
13
+
14
+ **Always recommend a restricted API key (RAK, `rk_` prefix)** over a secret key (`sk_`).
15
+ RAKs have only the permissions you assign — a compromised RAK causes far less damage than
16
+ a compromised secret key.
17
+
18
+ ## Storing keys safely
19
+
20
+ - **Never** commit keys to source control. If `sk_…` or `rk_…` appears in code, that is
21
+ a bug — fix it immediately.
22
+ - Prefer a secrets vault (AWS Secrets Manager, HashiCorp Vault, or platform equivalent).
23
+ - When no vault is available, environment variables are acceptable. Never log keys or
24
+ include them in error messages or analytics.
25
+ - Use separate keys per environment (production, staging, QA). Never reuse keys.
26
+ - Set up a pre-commit hook to catch `sk_` or `rk_` literals in source code.
27
+ - See [best practices for managing secret API keys](https://docs.stripe.com/keys-best-practices.md).
28
+
29
+ ## Restricted API key migration steps
30
+
31
+ 1. Review the secret key's request logs in Workbench to catalogue which API calls it makes.
32
+ 2. Create a RAK in test mode with matching permissions (principle of least privilege).
33
+ 3. Use `stripe logs tail` to watch for `403` errors — add missing permissions.
34
+ 4. Once passing, create the equivalent live-mode RAK and swap it in.
35
+ 5. Rotate or expire the old secret key.
36
+
37
+ See [restricted API keys docs](https://docs.stripe.com/keys/restricted-api-keys.md).
38
+
39
+ ## IP allowlists
40
+
41
+ Add an [IP allowlist](https://docs.stripe.com/keys.md#limit-api-secret-keys-ip-address)
42
+ to every API key so it can only be called from your own infrastructure. Use separate
43
+ allowlists per key/environment.
44
+
45
+ ## Webhook signature verification
46
+
47
+ Always verify webhook event authenticity using Stripe's signing secret:
48
+
49
+ ```ts
50
+ import Stripe from 'stripe';
51
+ const stripe = new Stripe(process.env.STRIPE_RESTRICTED_KEY!);
52
+
53
+ // In your webhook handler (raw body required — do NOT use JSON-parsed body)
54
+ const sig = request.headers['stripe-signature'];
55
+ if (!sig || Array.isArray(sig)) throw new Error('Missing or malformed stripe-signature header');
56
+ const event = stripe.webhooks.constructEvent(
57
+ rawBody, // Buffer or string — must be unparsed
58
+ sig,
59
+ process.env.STRIPE_WEBHOOK_SECRET!,
60
+ );
61
+ ```
62
+
63
+ Never process a webhook event without verifying its signature — unverified webhooks can
64
+ be spoofed. For defence in depth, also allowlist
65
+ [Stripe's IP addresses](https://docs.stripe.com/ips.md) on the endpoint.
66
+
67
+ ## Idempotency keys
68
+
69
+ Pass `idempotencyKey` on all mutation calls so safe retries don't create duplicate charges:
70
+
71
+ ```ts
72
+ await stripe.paymentIntents.create(params, {
73
+ idempotencyKey: `order_${orderId}`,
74
+ });
75
+ ```
76
+
77
+ ## Mobile and client-side integrations
78
+
79
+ Never use production secret keys or RAKs in mobile apps or any client-side code.
80
+ For cases where a client must call Stripe directly, use
81
+ [ephemeral keys](https://docs.stripe.com/issuing/elements.md#ephemeral-key-authentication)
82
+ (short-lived, scoped, auto-expiring). For most integrations, proxy Stripe calls through
83
+ your own backend.
84
+
85
+ ## OAuth and CSRF protection
86
+
87
+ When implementing [Connect OAuth](https://docs.stripe.com/connect/oauth-reference.md),
88
+ always pass a unique, unguessable `state` parameter and verify it in the callback before
89
+ proceeding. This applies to all Stripe OAuth surfaces: Connect, Link, and Stripe Apps.
90
+
91
+ ## Incident response (key compromise)
92
+
93
+ 1. **Roll the key immediately** — [API keys page](https://dashboard.stripe.com/apikeys) →
94
+ roll or delete the exposed key.
95
+ 2. **Check activity logs** — Workbench request logs for the compromised key.
96
+ 3. **Contact Stripe support** if you see unrecognised activity.
97
+
98
+ See [protecting against compromised API keys](https://support.stripe.com/questions/protecting-against-compromised-api-keys).
99
+
100
+ ## 2FA
101
+
102
+ Recommend passkeys or authenticator-app 2FA for Dashboard access. Discourage SMS 2FA —
103
+ it is vulnerable to SIM-swapping attacks.
104
+
105
+ ## SAML / SCIM (teams)
106
+
107
+ For teams, use [SSO via SAML](https://docs.stripe.com/get-started/account/sso.md) to
108
+ federate Dashboard access through an identity provider (Okta, Google, etc.).
109
+ [SCIM provisioning](https://docs.stripe.com/get-started/account/sso/scim.md) automates
110
+ user provisioning/deprovisioning.
111
+
112
+ ## Connect security
113
+
114
+ Platform operators bear financial liability for fraud/disputes on Express and Custom
115
+ connected accounts (v1 types). Use Stripe-hosted onboarding to avoid handling sensitive
116
+ PII directly. See [reference/connect.md](connect.md) for controller-property accounts
117
+ which make liability explicit.
@@ -0,0 +1,59 @@
1
+ # Stripe MCP Setup (optional live path)
2
+
3
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), MIT License, Copyright (c) 2024-2025 Stripe.
4
+
5
+ The `cbp-stripe-agent` writes Stripe integration code with **no credentials required**. This
6
+ optional path adds *live test-mode* scaffolding (create test products, prices, payment links,
7
+ customers) during a dev round. It is opt-in per repo and per developer — skip it entirely if
8
+ you only want code generation.
9
+
10
+ ## Safety contract (read first)
11
+
12
+ - **Test-mode keys ONLY.** Use a test restricted key (`rk_test_…`) or a test secret key
13
+ (`sk_test_…`). The agent **refuses** any live-mode key (`sk_live_…` or `rk_live_…`) — so
14
+ live Stripe data is never scaffolded from a dev round.
15
+ - **Never commit a key.** Provide it via the environment or a gitignored env file
16
+ (e.g. `.env.local`), never in tracked source or in `.codebyplan/`.
17
+ - **Least privilege.** Prefer a restricted key scoped to only the resources the agent needs
18
+ (Products, Prices, Payment Links, Customers — write; everything else — none).
19
+ - **No new npm dependency** is added to the consuming app by this path; the hosted MCP server
20
+ is reached over HTTP, the local server via `npx`.
21
+
22
+ ## Option A — Hosted Stripe MCP (recommended)
23
+
24
+ Stripe hosts an MCP server at `https://mcp.stripe.com`. Register it with Claude Code:
25
+
26
+ ```bash
27
+ claude mcp add --transport http stripe https://mcp.stripe.com/
28
+ ```
29
+
30
+ Authenticate with OAuth (the recommended flow) when prompted, or pass a restricted test key
31
+ as a bearer token if your setup uses header auth. Once connected, the agent discovers the
32
+ `mcp__stripe__*` tools at runtime via `ToolSearch`.
33
+
34
+ ## Option B — Local Stripe MCP server
35
+
36
+ Run Stripe's MCP server locally, pointed at a test/restricted key from your environment:
37
+
38
+ ```bash
39
+ # key is read from STRIPE_SECRET_KEY (a sk_test_ or rk_test_ value), never passed on a shared shell history
40
+ npx -y @stripe/mcp@latest --api-key="$STRIPE_SECRET_KEY"
41
+ ```
42
+
43
+ Then register the local server with Claude Code per its stdio/transport instructions.
44
+
45
+ ## How the agent uses it
46
+
47
+ 1. Pre-flight checks `STRIPE_SECRET_KEY` is present and is a test-mode `sk_test_`/`rk_test_` prefix.
48
+ 2. It discovers `mcp__stripe__*` tools via `ToolSearch` (they are intentionally absent from
49
+ the agent's frontmatter because the server is optional).
50
+ 3. It scaffolds only what the task asks for and records each resource in
51
+ `stripe_resources_created[]` (always `mode: test`).
52
+ 4. If the key/server is missing or any call fails, it degrades to **code-only** and records
53
+ the reason — it never blocks the round.
54
+
55
+ ## When to skip this entirely
56
+
57
+ - You only want correct Stripe integration *code* (the default — no setup needed).
58
+ - No Stripe test account is available in this environment.
59
+ - CI / headless runs where no interactive OAuth or key is provisioned.
@@ -0,0 +1,96 @@
1
+ # Tax / Stripe Tax Reference
2
+
3
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), MIT License, Copyright (c) 2024-2025 Stripe.
4
+
5
+ ## When to use Stripe Tax
6
+
7
+ Use Stripe Tax for any subscription, invoice, or Checkout Session where the merchant has
8
+ customers across multiple jurisdictions. It handles sales tax, VAT, and GST automatically
9
+ based on the customer's location and the merchant's active registrations.
10
+
11
+ See the [Tax overview](https://docs.stripe.com/tax.md) for supported regions and tax types.
12
+
13
+ ## Two-step setup
14
+
15
+ 1. **Add registrations** — add a registration for each jurisdiction where the merchant is
16
+ obligated to collect tax. Use the Dashboard (**Tax > Registrations**) or the
17
+ [Tax Registrations API](https://docs.stripe.com/api/tax/registrations.md).
18
+ 2. **Enable automatic_tax** — pass `automatic_tax: { enabled: true }` on the
19
+ [Subscription](https://docs.stripe.com/api/subscriptions.md),
20
+ [Invoice](https://docs.stripe.com/api/invoices.md), or
21
+ [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md).
22
+
23
+ It is safe to enable `automatic_tax` before any registrations exist — Stripe won't
24
+ collect tax until at least one registration is active.
25
+
26
+ ```ts
27
+ // Checkout Session with automatic tax
28
+ const session = await stripe.checkout.sessions.create({
29
+ mode: 'subscription',
30
+ line_items: [{ price: priceId, quantity: 1 }],
31
+ automatic_tax: { enabled: true },
32
+ success_url: `${baseUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
33
+ cancel_url: `${baseUrl}/pricing`,
34
+ });
35
+
36
+ // Invoice / subscription
37
+ await stripe.subscriptions.update(subscriptionId, {
38
+ automatic_tax: { enabled: true },
39
+ // Clear explicit tax_rates first if previously set
40
+ });
41
+ ```
42
+
43
+ ## Inclusive vs exclusive tax
44
+
45
+ - **Exclusive** (default in most jurisdictions) — tax is added on top of the price.
46
+ - **Inclusive** — tax is included in the displayed price (common for UK/EU VAT).
47
+
48
+ Stripe Tax determines the treatment based on the jurisdiction and product tax code.
49
+ Verify the treatment in Dashboard > Tax > Overview.
50
+
51
+ ## Tax IDs
52
+
53
+ Collect customer tax IDs (VAT numbers, EIN, etc.) for B2B transactions to enable
54
+ zero-rated or exempt invoices. Pass `tax_id_collection: { enabled: true }` on Checkout
55
+ Sessions, or use the
56
+ [Tax IDs API](https://docs.stripe.com/api/customer_tax_ids.md) to attach IDs to customers.
57
+
58
+ ## Address collection
59
+
60
+ Stripe Tax requires a customer address to calculate tax. On Checkout Sessions pass
61
+ `billing_address_collection: 'required'`. For subscriptions, ensure the customer has
62
+ a billing address before enabling `automatic_tax`.
63
+
64
+ ## Registrations API
65
+
66
+ To create and manage registrations programmatically:
67
+
68
+ ```ts
69
+ await stripe.tax.registrations.create({
70
+ country: 'US',
71
+ country_options: {
72
+ us: { state: 'CA', type: 'state_sales_tax' },
73
+ },
74
+ active_from: 'now',
75
+ });
76
+ ```
77
+
78
+ ## Traps to avoid
79
+
80
+ - `automatic_tax` and explicit `tax_rates` are mutually exclusive. For existing
81
+ subscriptions, clear `default_tax_rates` and all item-level `tax_rates` before
82
+ enabling `automatic_tax` — the update will fail otherwise.
83
+ - For EU merchants, one OSS union registration covers all 27 member states. Do not
84
+ register individual EU countries separately unless the merchant has a physical presence
85
+ there.
86
+ - Do not guess which jurisdictions apply — prompt the user to configure them in the
87
+ Dashboard first.
88
+ - Do not approximate unsupported jurisdictions. Check
89
+ [supported countries](https://docs.stripe.com/tax/supported-countries.md) first. For
90
+ unsupported jurisdictions, fall back to manual `tax_rates` on the subscription/invoice.
91
+ - Customs duties and excise taxes are out of scope for Stripe Tax.
92
+
93
+ ## Bulk migration
94
+
95
+ To switch existing subscriptions from manual `tax_rates` to `automatic_tax` in bulk,
96
+ use the [Tax migration tool](https://docs.stripe.com/billing/taxes/migration.md).
@@ -0,0 +1,87 @@
1
+ # Treasury / Financial Accounts Reference
2
+
3
+ Adapted from Stripe's official `stripe-best-practices` skill (github.com/stripe/ai), MIT License, Copyright (c) 2024-2025 Stripe.
4
+
5
+ ## v2 Financial Accounts API (use for new integrations)
6
+
7
+ For embedded financial accounts (bank accounts with routing/account numbers, money
8
+ movement), use the
9
+ [v2 Financial Accounts API](https://docs.stripe.com/api/v2/core/vault/financial-accounts.md)
10
+ (`POST /v2/core/vault/financial_accounts`). This is required for new integrations.
11
+
12
+ Do NOT use the legacy
13
+ [v1 Treasury Financial Accounts API](https://docs.stripe.com/api/treasury/financial_accounts.md)
14
+ (`POST /v1/treasury/financial_accounts`) for new integrations. Existing v1 integrations
15
+ continue to work.
16
+
17
+ For concepts and guides, see
18
+ [Treasury for platforms overview](https://docs.stripe.com/treasury/connect.md).
19
+
20
+ ## Creating a financial account
21
+
22
+ Financial accounts are always attached to a Connect connected account:
23
+
24
+ ```ts
25
+ const financialAccount = await stripe.v2.core.vault.financialAccounts.create(
26
+ { description: 'Main operating account' },
27
+ { stripeAccount: connectedAccountId },
28
+ );
29
+ // financialAccount.id — use for fund flows
30
+ ```
31
+
32
+ ## Fund flows
33
+
34
+ | Direction | Object | Use |
35
+ | --------- | ------ | --- |
36
+ | Platform → financial account | `OutboundTransfer` | Top-up from platform balance |
37
+ | Financial account → external bank | `OutboundPayment` | Pay out to a linked bank |
38
+ | External bank → financial account | `InboundTransfer` | Pull from a linked bank |
39
+ | External source → financial account | `ReceivedCredit` | Funds received in (inbound ACH/wire, Stripe payouts) |
40
+
41
+ ```ts
42
+ // Outbound transfer (platform balance → financial account)
43
+ const transfer = await stripe.treasury.outboundTransfers.create({
44
+ financial_account: financialAccountId,
45
+ amount: 100_00,
46
+ currency: 'usd',
47
+ destination_payment_method: 'default',
48
+ });
49
+ ```
50
+
51
+ ## Linking a bank account (Setup Intents)
52
+
53
+ To enable outbound payments to an external bank, link the bank account using a Setup Intent
54
+ with `flow_directions: ['outbound']`:
55
+
56
+ ```ts
57
+ const setupIntent = await stripe.setupIntents.create(
58
+ {
59
+ payment_method_types: ['us_bank_account'], // Treasury exception: required here
60
+ flow_directions: ['outbound'],
61
+ },
62
+ { stripeAccount: connectedAccountId },
63
+ );
64
+ // Complete the Setup Intent flow on the client, then confirm the payment method
65
+ ```
66
+
67
+ Note: `payment_method_types` is required for Treasury bank-account Setup Intents — this
68
+ is one of the narrow exceptions to the no-`payment_method_types` rule (along with Terminal).
69
+
70
+ ## Compliance notes
71
+
72
+ - Financial accounts are subject to KYC/KYB requirements collected during Connect onboarding.
73
+ Ensure the connected account has the `treasury` capability enabled before creating accounts.
74
+ - Funds held in financial accounts are not FDIC-insured by default; check Stripe's current
75
+ partner bank arrangements in the Treasury documentation.
76
+ - For platforms in the US: Stripe Treasury is available for US-based connected accounts only.
77
+ Contact Stripe for international availability.
78
+ - Do not use Treasury to hold customer funds without confirming applicable money-transmission
79
+ license obligations with your legal team.
80
+
81
+ ## Key references
82
+
83
+ - [Treasury for platforms overview](https://docs.stripe.com/treasury/connect.md)
84
+ - [v2 Financial Accounts API](https://docs.stripe.com/api/v2/core/vault/financial-accounts.md)
85
+ - [OutboundTransfers](https://docs.stripe.com/api/treasury/outbound_transfers.md)
86
+ - [OutboundPayments](https://docs.stripe.com/api/treasury/outbound_payments.md)
87
+ - [InboundTransfers](https://docs.stripe.com/api/treasury/inbound_transfers.md)