Merge branch 'dev' into feat/store-line-items

This commit is contained in:
John Yeo
2026-02-26 10:49:35 +00:00
213 changed files with 18436 additions and 5203 deletions

View File

@@ -0,0 +1,99 @@
---
description: Filter (hide) fields from an API response so they are not visible to external SDK consumers
argument-hint: [schema-name] [field1, field2, ...]
---
# Filter Response Fields
Hide internal fields from external API responses using the response filter middleware. The middleware runs on all `/v1/*` API routes and recursively strips specified fields from JSON responses. Dashboard requests are automatically bypassed.
## How it works
The response filter uses an `object` discriminator field on each JSON object in the response to determine which filter rules to apply. At runtime, the middleware walks the entire response tree, and for each object with an `object` field, it looks up that value in `responseFilterConfig` to find which fields to strip.
## Steps
### 1. Add `object` literal to the Zod schema
In the schema file (under `shared/`), add an `object` field with a `z.literal()` value:
```typescript
export const MyResponseSchema = z.object({
object: z.literal("my_response").meta({ internal: true }),
// ... existing fields
secret_field: z.string().meta({ internal: true }),
});
```
- The `object` value should be a snake_case identifier for this schema
- Mark it `.meta({ internal: true })` so it's also excluded from OpenAPI docs
- The schema **must be exported** (so it can be imported into the filter config)
### 2. Add `object` to all construction sites
Find every place in `server/` that constructs objects of this type and add the `object` field:
```typescript
return {
object: "my_response" as const,
// ... existing fields
};
```
Search for:
- Functions with the return type annotation (e.g., `): MyResponse =>`)
- `satisfies MyResponse` patterns
- Spread patterns that assemble the type inline (e.g., `{ ...baseResponse, extra_field }`)
### 3. Register in the filter config
In `server/src/honoMiddlewares/responseFilter/responseFilterConfig.ts`:
1. Import the schema and its inferred type from `@autumn/shared`
2. Add a `createFilterConfig` entry to the `filterConfigs` array
```typescript
createFilterConfig<MyResponse>({
schema: MyResponseSchema,
omitFields: ["secret_field", "object"],
}),
```
Always include `"object"` in `omitFields` so the discriminator itself is stripped from external responses.
## Gotcha: Schema inheritance
When a schema extends another (e.g., `AttachPreviewResponseSchema` extends `BillingPreviewResponseSchema`), each schema has its **own** `object` literal value. At runtime, the response will only have **one** `object` value -- the most derived one.
This means: **fields inherited from the parent schema must be listed in the child's `omitFields` too**, not just the parent's.
Example:
```typescript
// Parent schema has object: "billing_preview"
// - omitFields: ["period_start", "period_end", "object"]
// Child schema has object: "attach_preview" (overrides parent's object)
// - MUST also include parent's filtered fields:
// - omitFields: ["redirect_type", "incoming", "outgoing", "object", "period_start", "period_end"]
```
The child's `object` literal **overrides** the parent's, so the middleware will only match the child's filter config -- it will never see `"billing_preview"` on an attach preview response. If you forget to duplicate the parent's omitted fields in the child config, those fields will leak through.
## Key files
- **Schema definitions**: `shared/api/` (wherever the Zod schema lives)
- **Filter config**: `server/src/honoMiddlewares/responseFilter/responseFilterConfig.ts`
- **Filter middleware**: `server/src/honoMiddlewares/responseFilter/responseFilterMiddleware.ts`
- **Dashboard bypass**: The middleware checks `ctx.authType === AuthType.Dashboard` and skips filtering, so dashboard requests always receive the full unfiltered response.
## Checklist
- [ ] Added `object: z.literal("...").meta({ internal: true })` to the schema
- [ ] Schema is exported from its file and re-exported from `@autumn/shared`
- [ ] Added `object: "..." as const` to every place that constructs this type
- [ ] Added `createFilterConfig` entry in `responseFilterConfig.ts`
- [ ] Included `"object"` in the `omitFields` array
- [ ] If schema extends another filtered schema, duplicated parent's `omitFields` in child config
- [ ] Verified with an API request that filtered fields are stripped
- [ ] Verified dashboard still receives unfiltered response

View File

@@ -0,0 +1,71 @@
---
description: Update an existing autumn-js route after changes to its API contract, params, or response shape
argument-hint: [route-name e.g. attach, multiAttach, setupPayment]
---
# Update Autumn JS Route
When modifying an existing API endpoint (params, response shape, JSDoc, etc.), check **all** of these locations for consistency.
## Architecture
Request flow from React hook to Autumn API:
```
React Hook (useCustomer)
→ useCustomerActions (redirect logic, URL defaults)
→ AutumnClient / httpClient (POST /api/autumn/{routeName})
→ rou3 router (routeBuilder.ts)
→ executeRoute (resolveIdentity → inject customerId → SDK method)
→ @useautumn/sdk → Autumn API
```
- The **backend** is a thin proxy. `routeConfigs.ts` maps route names to `@useautumn/sdk` methods. `executeRoute.ts` auto-injects `customerId` from `resolveIdentity()` before calling the SDK.
- The **React client** (`AutumnClient.ts`) sends POST requests to `{pathPrefix}/{routeName}` with the body as JSON. The route name IS the URL segment (e.g. `multiAttach` maps to `POST /api/autumn/multiAttach`).
- **`useCustomerActions`** wraps client methods with redirect logic and `window.location.href` defaults. It bridges the TanStack Query-based `useCustomer` hook and the imperative billing actions.
## Files to inspect and update
| Layer | File | What to check |
|-------|------|---------------|
| ORPC contract | `packages/openapi/v2.1/contracts/billingContract.ts` | Input/output schemas match changes |
| Generated schemas | `packages/autumn-js/src/generated/` | Re-run `bun api` if contract changed |
| Client params | `packages/autumn-js/src/types/params.ts` | Omit/extend fields still correct |
| Type exports | `packages/autumn-js/src/types/index.ts` | Alias still matches |
| React exports | `packages/autumn-js/src/react/index.ts` | Client param type exported |
| Route names | `packages/autumn-js/src/backend/core/types/routeTypes.ts` | `ROUTE_NAMES` has the route |
| Route config | `packages/autumn-js/src/backend/core/routes/routeConfigs.ts` | `sdkMethod` and `bodySchema` still match |
| Client interface | `packages/autumn-js/src/react/client/IAutumnClient.ts` | Method signature matches new types |
| Client impl | `packages/autumn-js/src/react/client/AutumnClient.ts` | Response type matches |
| Hook actions | `packages/autumn-js/src/react/hooks/internal/useCustomerActions.ts` | Action logic handles new fields (redirects, defaults) |
| Hook JSDoc | `packages/autumn-js/src/react/hooks/useCustomer.ts` | `UseCustomerResult` JSDoc describes current behavior |
| Zod schema gen | `packages/openapi/utils/zodSchemaGeneration.ts` | `SCHEMA_SOURCES` sdkFile/outputFile match current SDK model filenames |
| SDK test page | `apps/sdk-test/app/scenarios/core/use-autumn/page.tsx` | Test UI exposes new/changed params |
## Common update scenarios
**Param added/removed**: Update `params.ts` type -> check `useCustomerActions` passes it -> update sdk-test inputs.
**Response shape changed**: Update `IAutumnClient` + `AutumnClient` return types -> update `useCustomer.ts` JSDoc.
**Redirect behavior changed**: Check `useCustomerActions` redirect logic (`paymentUrl`, `url`, `openInNewTab`).
**JSDoc only**: Update `useCustomer.ts` `UseCustomerResult` type and the hook's `@returns` summary.
## Gotchas
- **Casing**: The SDK uses camelCase everywhere. The backend `buildSdkArgs` passes camelCase directly to the SDK. Never use snake_case in `params.ts`, `IAutumnClient.ts`, or hook types.
- **`ProtectedFields`**: Client param types always `Omit<SdkParams, "customerId" | "customerData">`. The backend injects these via `resolveIdentity`. If you add a new field that should NOT be set by the frontend, add it to the Omit union.
- **`openInNewTab`**: Frontend-only field (not sent to the API). Added via `& { openInNewTab?: boolean }` on client param types that trigger redirects (`attach`, `multiAttach`, `setupPayment`, `updateSubscription`, `openCustomerPortal`). The `useCustomerActions` layer reads it and calls `redirectToUrl`.
- **`successUrl` / `returnUrl` defaults**: Actions in `useCustomerActions` default these to `window.location.href`. If you change this default, update all actions consistently.
- **Route name must match everywhere**: The string in `ROUTE_NAMES`, `routeConfigs[].route`, `AutumnClient`'s `http.request({ route: "..." })`, and the rou3 path segment must all be identical.
- **`bodySchema` is optional**: Only needed if the route is used via the better-auth plugin. Standard routes work without it.
- **Response types come from `@useautumn/sdk`**: Don't create custom response types. Import from the SDK (e.g. `AttachResponse`, `SetupPaymentResponse`). These are auto-generated by Speakeasy.
- **Generated schemas** in `packages/autumn-js/src/generated/` are only for `bodySchema` validation in better-auth. Not all routes need them.
- **operationId renames cause SDK file renames**: When you change an `operationId` in a contract (e.g. `billingAttach``attach`), Speakeasy renames the generated model file (e.g. `billing-attach-op.ts``attach-op.ts`) and all its exported types (e.g. `BillingAttachResponse``AttachResponse`). You **must** update: (1) `packages/openapi/utils/zodSchemaGeneration.ts` — change the `sdkFile` and `outputFile` in `SCHEMA_SOURCES`, (2) delete the old generated schema file from `packages/autumn-js/src/generated/`, and (3) update all imports of the old type names across `IAutumnClient.ts`, `AutumnClient.ts`, `useCustomerActions.ts`, and `useCustomer.ts`.
## Validation
```bash
bunx biome check --write <paths to changed files>
```

View File

@@ -29,6 +29,10 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
Add this amount to the current balance. Use negative values to subtract. Cannot be combined with current_balance.
</DynamicParamField>
<DynamicParamField body="usage" type="number">
The usage amount to update. Cannot be combined with remaining or add_to_balance.
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Target a specific balance by its reset interval. Use when the customer has multiple balances for the same feature with different reset intervals.
</DynamicParamField>

View File

@@ -7,24 +7,79 @@ import { DynamicParamField } from "/components/dynamic-param-field.jsx";
import { DynamicResponseField } from "/components/dynamic-response-field.jsx";
import { DynamicResponseExample } from "/components/dynamic-response-example.jsx";
<Note>
The attach endpoint subscribes a customer to a plan. It handles new subscriptions, upgrades, and downgrades automatically. For modifying an existing subscription (like changing quantities or canceling), use [update](/api-reference/billing/billingUpdate) instead.
</Note>
### Common Use Cases
<CodeGroup>
```typescript Subscribe to a plan
const response = await autumn.billing.attach({
customerId: "cus_123",
planId: "pro_plan"
});
if (response.paymentUrl) {
// Redirect customer to checkout
window.location.href = response.paymentUrl;
}
```
```typescript Custom pricing
const response = await autumn.billing.attach({
customerId: "cus_123",
planId: "enterprise_plan",
customize: {
price: {
amount: 99900, // $999.00
interval: "month"
}
}
});
```
```typescript Attach plan with prepaid quantities
const response = await autumn.billing.attach({
customerId: "cus_123",
planId: "team_plan",
featureQuantities: [
{ featureId: "seats", quantity: 5 }
]
});
```
</CodeGroup>
### Body Parameters
<DynamicParamField body="customer_id" type="string" required>
The ID of the customer to attach the plan to.
</DynamicParamField>
<DynamicParamField body="entity_id" type="string | null">
<DynamicParamField body="entity_id" type="string">
The ID of the entity to attach the plan to.
</DynamicParamField>
<DynamicParamField body="feature_quantities" type="object[] | null">
<DynamicParamField body="plan_id" type="string" required>
The ID of the plan.
</DynamicParamField>
<DynamicParamField body="feature_quantities" type="object[]">
If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required />
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to set quantity for.
</DynamicParamField>
<DynamicParamField body="quantity" type="number" />
<DynamicParamField body="quantity" type="number">
The quantity of the feature.
</DynamicParamField>
<DynamicParamField body="adjustable" type="boolean" />
<DynamicParamField body="adjustable" type="boolean">
Whether the customer can adjust the quantity.
</DynamicParamField>
</Expandable>
</DynamicParamField>
@@ -33,90 +88,128 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
The version of the plan to attach.
</DynamicParamField>
<DynamicParamField body="free_trial" type="object | null">
<Expandable title="properties">
<DynamicParamField body="duration_length" type="number" required />
<DynamicParamField body="duration_type" type="'day' | 'month' | 'year'" />
<DynamicParamField body="card_required" type="boolean" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="customize" type="object">
Customize the plan to attach. Can either override the price of the plan, the items in the plan, or both.
Customize the plan to attach. Can override the price, items, free trial, or a combination.
<Expandable title="properties">
<DynamicParamField body="price" type="object | null">
Base price configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="amount" type="number" required>
Base price amount for the plan.
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval (e.g. 'month', 'year').
</DynamicParamField>
<DynamicParamField body="interval_count" type="number" />
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="items" type="object[]">
Override the items in the plan.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required />
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to configure.
</DynamicParamField>
<DynamicParamField body="included" type="number" />
<DynamicParamField body="included" type="number">
Number of free units included. Balance resets to this each interval for consumable features.
</DynamicParamField>
<DynamicParamField body="unlimited" type="boolean" />
<DynamicParamField body="unlimited" type="boolean">
If true, customer has unlimited access to this feature.
</DynamicParamField>
<DynamicParamField body="reset" type="object">
Reset configuration for consumable features. Omit for non-consumable features like seats.
<Expandable title="properties">
<DynamicParamField body="interval" type="'one_off' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required />
<DynamicParamField body="interval" type="'one_off' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number" />
<DynamicParamField body="interval_count" type="number">
Number of intervals between resets. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="price" type="object">
Pricing for usage beyond included units. Omit for free features.
<Expandable title="properties">
<DynamicParamField body="amount" type="number" />
<DynamicParamField body="amount" type="number">
Price per billing_units after included usage. Either 'amount' or 'tiers' is required.
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required />
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval_count" type="number" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
<DynamicParamField body="billing_units" type="number" />
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
<DynamicParamField body="billing_method" type="'prepaid' | 'usage_based'" required />
<DynamicParamField body="billing_units" type="number">
Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200).
</DynamicParamField>
<DynamicParamField body="max_purchase" type="number" />
<DynamicParamField body="billing_method" type="'prepaid' | 'usage_based'" required>
'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
</DynamicParamField>
<DynamicParamField body="max_purchase" type="number">
Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="proration" type="object">
Proration settings for prepaid features. Controls mid-cycle quantity change billing.
<Expandable title="properties">
<DynamicParamField body="on_increase" type="'bill_immediately' | 'prorate_immediately' | 'prorate_next_cycle' | 'bill_next_cycle'" required />
<DynamicParamField body="on_increase" type="'bill_immediately' | 'prorate_immediately' | 'prorate_next_cycle' | 'bill_next_cycle'" required>
Billing behavior when quantity increases mid-cycle.
</DynamicParamField>
<DynamicParamField body="on_decrease" type="'prorate' | 'prorate_immediately' | 'prorate_next_cycle' | 'none' | 'no_prorations'" required />
<DynamicParamField body="on_decrease" type="'prorate' | 'prorate_immediately' | 'prorate_next_cycle' | 'none' | 'no_prorations'" required>
Credit behavior when quantity decreases mid-cycle.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="rollover" type="object">
Rollover config for unused units. If set, unused included units carry over.
<Expandable title="properties">
<DynamicParamField body="max" type="number" />
<DynamicParamField body="max" type="number">
Max rollover units. Omit for unlimited rollover.
</DynamicParamField>
<DynamicParamField body="expiry_duration_type" type="'month' | 'forever'" required />
<DynamicParamField body="expiry_duration_type" type="'month' | 'forever'" required>
When rolled over units expire.
</DynamicParamField>
<DynamicParamField body="expiry_duration_length" type="number" />
<DynamicParamField body="expiry_duration_length" type="number">
Number of periods before expiry.
</DynamicParamField>
</Expandable>
</DynamicParamField>
@@ -124,63 +217,130 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</Expandable>
</DynamicParamField>
<DynamicParamField body="free_trial" type="object | null">
Free trial configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="duration_length" type="number" required>
Number of duration_type periods the trial lasts.
</DynamicParamField>
<DynamicParamField body="duration_type" type="'day' | 'month' | 'year'">
Unit of time for the trial ('day', 'month', 'year').
</DynamicParamField>
<DynamicParamField body="card_required" type="boolean">
If true, payment method required to start trial. Customer is charged after trial ends.
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="plan_id" type="string" required />
<DynamicParamField body="invoice_mode" type="object">
Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. This uses Stripe's send_invoice collection method.
<Expandable title="properties">
<DynamicParamField body="enabled" type="boolean" required />
<DynamicParamField body="enabled" type="boolean" required>
When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method.
</DynamicParamField>
<DynamicParamField body="enable_plan_immediately" type="boolean" />
<DynamicParamField body="enable_plan_immediately" type="boolean">
If true, enables the plan immediately even though the invoice is not paid yet.
</DynamicParamField>
<DynamicParamField body="finalize" type="boolean" />
<DynamicParamField body="finalize" type="boolean">
If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="discounts" type="object[]" />
<DynamicParamField body="proration_behavior" type="'prorate_immediately' | 'none'">
How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges.
</DynamicParamField>
<DynamicParamField body="redirect_mode" type="'always' | 'if_required' | 'never'" />
<DynamicParamField body="discounts" type="object[]">
List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code.
<Expandable title="properties">
<DynamicParamField body="reward_id" type="string">
The ID of the reward to apply as a discount.
</DynamicParamField>
<DynamicParamField body="success_url" type="string" />
<DynamicParamField body="promotion_code" type="string">
The promotion code to apply as a discount.
</DynamicParamField>
<DynamicParamField body="new_billing_subscription" type="boolean" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="plan_schedule" type="'immediate' | 'end_of_cycle'" />
<DynamicParamField body="success_url" type="string">
URL to redirect to after successful checkout.
</DynamicParamField>
<DynamicParamField body="billing_behavior" type="'prorate_immediately' | 'next_cycle_only'" />
<DynamicParamField body="new_billing_subscription" type="boolean">
Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
</DynamicParamField>
<DynamicParamField body="plan_schedule" type="'immediate' | 'end_of_cycle'">
When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled.
</DynamicParamField>
<DynamicParamField body="checkout_session_params" type="object">
Additional parameters to pass into the creation of the Stripe checkout session.
</DynamicParamField>
### Response
<DynamicResponseField name="customer_id" type="string" />
<DynamicResponseField name="customer_id" type="string">
The ID of the customer.
</DynamicResponseField>
<DynamicResponseField name="entity_id" type="string" />
<DynamicResponseField name="entity_id" type="string">
The ID of the entity, if the plan was attached to an entity.
</DynamicResponseField>
<DynamicResponseField name="invoice" type="object">
Invoice details if an invoice was created. Only present when a charge was made.
<Expandable title="properties">
<DynamicResponseField name="status" type="string | null" />
<DynamicResponseField name="status" type="string | null">
The status of the invoice (e.g., 'paid', 'open', 'draft').
</DynamicResponseField>
<DynamicResponseField name="stripe_id" type="string" />
<DynamicResponseField name="stripe_id" type="string">
The Stripe invoice ID.
</DynamicResponseField>
<DynamicResponseField name="total" type="number" />
<DynamicResponseField name="total" type="number">
The total amount of the invoice in cents.
</DynamicResponseField>
<DynamicResponseField name="currency" type="string" />
<DynamicResponseField name="currency" type="string">
The three-letter ISO currency code (e.g., 'usd').
</DynamicResponseField>
<DynamicResponseField name="hosted_invoice_url" type="string | null" />
<DynamicResponseField name="hosted_invoice_url" type="string | null">
URL to the hosted invoice page where the customer can view and pay the invoice.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="payment_url" type="string | null" />
<DynamicResponseField name="payment_url" type="string | null">
URL to redirect the customer to complete payment. Null if no payment action is required.
</DynamicResponseField>
<DynamicResponseField name="required_action" type="object">
Details about any action required to complete the payment. Present when the payment could not be processed automatically.
<Expandable title="properties">
<DynamicResponseField name="code" type="'3ds_required' | 'payment_method_required' | 'payment_failed'" />
<DynamicResponseField name="code" type="'3ds_required' | 'payment_method_required' | 'payment_failed'">
The type of action required to complete the payment.
</DynamicResponseField>
<DynamicResponseField name="reason" type="string" />
<DynamicResponseField name="reason" type="string">
A human-readable explanation of why this action is required.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -190,7 +350,7 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
```json 200
{
"customer_id": "cus_123",
"payment_url": null
"payment_url": "https://checkout.stripe.com/..."
}
```
</ResponseExample>

View File

@@ -1,348 +0,0 @@
---
title: "Attach"
openapi: "openapi POST /v1/billing.attach"
---
import { DynamicParamField } from "/components/dynamic-param-field.jsx";
import { DynamicResponseField } from "/components/dynamic-response-field.jsx";
import { DynamicResponseExample } from "/components/dynamic-response-example.jsx";
<Note>
The attach endpoint subscribes a customer to a plan. It handles new subscriptions, upgrades, and downgrades automatically. For modifying an existing subscription (like changing quantities or canceling), use [update](/api-reference/billing/billingUpdate) instead.
</Note>
### Common Use Cases
<CodeGroup>
```typescript Subscribe to a plan
const response = await autumn.billing.attach({
customerId: "cus_123",
planId: "pro_plan"
});
if (response.paymentUrl) {
// Redirect customer to checkout
window.location.href = response.paymentUrl;
}
```
```typescript Custom pricing
const response = await autumn.billing.attach({
customerId: "cus_123",
planId: "enterprise_plan",
customize: {
price: {
amount: 99900, // $999.00
interval: "month"
}
}
});
```
```typescript Attach plan with prepaid quantities
const response = await autumn.billing.attach({
customerId: "cus_123",
planId: "team_plan",
featureQuantities: [
{ featureId: "seats", quantity: 5 }
]
});
```
</CodeGroup>
### Body Parameters
<DynamicParamField body="customer_id" type="string" required>
The ID of the customer to attach the plan to.
</DynamicParamField>
<DynamicParamField body="entity_id" type="string">
The ID of the entity to attach the plan to.
</DynamicParamField>
<DynamicParamField body="plan_id" type="string" required>
The ID of the plan.
</DynamicParamField>
<DynamicParamField body="feature_quantities" type="object[]">
If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to set quantity for.
</DynamicParamField>
<DynamicParamField body="quantity" type="number">
The quantity of the feature.
</DynamicParamField>
<DynamicParamField body="adjustable" type="boolean">
Whether the customer can adjust the quantity.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="version" type="number">
The version of the plan to attach.
</DynamicParamField>
<DynamicParamField body="customize" type="object">
Customize the plan to attach. Can override the price, items, free trial, or a combination.
<Expandable title="properties">
<DynamicParamField body="price" type="object | null">
Base price configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="amount" type="number" required>
Base price amount for the plan.
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval (e.g. 'month', 'year').
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="items" type="object[]">
Override the items in the plan.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to configure.
</DynamicParamField>
<DynamicParamField body="included" type="number">
Number of free units included. Balance resets to this each interval for consumable features.
</DynamicParamField>
<DynamicParamField body="unlimited" type="boolean">
If true, customer has unlimited access to this feature.
</DynamicParamField>
<DynamicParamField body="reset" type="object">
Reset configuration for consumable features. Omit for non-consumable features like seats.
<Expandable title="properties">
<DynamicParamField body="interval" type="'one_off' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals between resets. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="price" type="object">
Pricing for usage beyond included units. Omit for free features.
<Expandable title="properties">
<DynamicParamField body="amount" type="number">
Price per billing_units after included usage. Either 'amount' or 'tiers' is required.
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
</Expandable>
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
<DynamicParamField body="billing_units" type="number">
Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200).
</DynamicParamField>
<DynamicParamField body="billing_method" type="'prepaid' | 'usage_based'" required>
'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
</DynamicParamField>
<DynamicParamField body="max_purchase" type="number">
Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="proration" type="object">
Proration settings for prepaid features. Controls mid-cycle quantity change billing.
<Expandable title="properties">
<DynamicParamField body="on_increase" type="'bill_immediately' | 'prorate_immediately' | 'prorate_next_cycle' | 'bill_next_cycle'" required>
Billing behavior when quantity increases mid-cycle.
</DynamicParamField>
<DynamicParamField body="on_decrease" type="'prorate' | 'prorate_immediately' | 'prorate_next_cycle' | 'none' | 'no_prorations'" required>
Credit behavior when quantity decreases mid-cycle.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="rollover" type="object">
Rollover config for unused units. If set, unused included units carry over.
<Expandable title="properties">
<DynamicParamField body="max" type="number">
Max rollover units. Omit for unlimited rollover.
</DynamicParamField>
<DynamicParamField body="expiry_duration_type" type="'month' | 'forever'" required>
When rolled over units expire.
</DynamicParamField>
<DynamicParamField body="expiry_duration_length" type="number">
Number of periods before expiry.
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="free_trial" type="object | null">
Free trial configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="duration_length" type="number" required>
Number of duration_type periods the trial lasts.
</DynamicParamField>
<DynamicParamField body="duration_type" type="'day' | 'month' | 'year'">
Unit of time for the trial ('day', 'month', 'year').
</DynamicParamField>
<DynamicParamField body="card_required" type="boolean">
If true, payment method required to start trial. Customer is charged after trial ends.
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="invoice_mode" type="object">
Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. This uses Stripe's send_invoice collection method.
<Expandable title="properties">
<DynamicParamField body="enabled" type="boolean" required>
When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method.
</DynamicParamField>
<DynamicParamField body="enable_plan_immediately" type="boolean">
If true, enables the plan immediately even though the invoice is not paid yet.
</DynamicParamField>
<DynamicParamField body="finalize" type="boolean">
If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="proration_behavior" type="'prorate_immediately' | 'none'">
How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges.
</DynamicParamField>
<DynamicParamField body="discounts" type="object[]">
List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code.
<Expandable title="properties">
<DynamicParamField body="reward_id" type="string">
The ID of the reward to apply as a discount.
</DynamicParamField>
<DynamicParamField body="promotion_code" type="string">
The promotion code to apply as a discount.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="success_url" type="string">
URL to redirect to after successful checkout.
</DynamicParamField>
<DynamicParamField body="new_billing_subscription" type="boolean">
Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
</DynamicParamField>
<DynamicParamField body="plan_schedule" type="'immediate' | 'end_of_cycle'">
When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled.
</DynamicParamField>
### Response
<DynamicResponseField name="customer_id" type="string">
The ID of the customer.
</DynamicResponseField>
<DynamicResponseField name="entity_id" type="string">
The ID of the entity, if the plan was attached to an entity.
</DynamicResponseField>
<DynamicResponseField name="invoice" type="object">
Invoice details if an invoice was created. Only present when a charge was made.
<Expandable title="properties">
<DynamicResponseField name="status" type="string | null">
The status of the invoice (e.g., 'paid', 'open', 'draft').
</DynamicResponseField>
<DynamicResponseField name="stripe_id" type="string">
The Stripe invoice ID.
</DynamicResponseField>
<DynamicResponseField name="total" type="number">
The total amount of the invoice in cents.
</DynamicResponseField>
<DynamicResponseField name="currency" type="string">
The three-letter ISO currency code (e.g., 'usd').
</DynamicResponseField>
<DynamicResponseField name="hosted_invoice_url" type="string | null">
URL to the hosted invoice page where the customer can view and pay the invoice.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="payment_url" type="string | null">
URL to redirect the customer to complete payment. Null if no payment action is required.
</DynamicResponseField>
<DynamicResponseField name="required_action" type="object">
Details about any action required to complete the payment. Present when the payment could not be processed automatically.
<Expandable title="properties">
<DynamicResponseField name="code" type="'3ds_required' | 'payment_method_required' | 'payment_failed'">
The type of action required to complete the payment.
</DynamicResponseField>
<DynamicResponseField name="reason" type="string">
A human-readable explanation of why this action is required.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<ResponseExample>
```json 200
{
"customer_id": "cus_123",
"payment_url": "https://checkout.stripe.com/..."
}
```
</ResponseExample>

View File

@@ -135,15 +135,19 @@ const response = await autumn.billing.update({
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>

View File

@@ -0,0 +1,371 @@
---
title: "Multi Attach"
openapi: "openapi POST /v1/billing.multi_attach"
---
import { DynamicParamField } from "/components/dynamic-param-field.jsx";
import { DynamicResponseField } from "/components/dynamic-response-field.jsx";
import { DynamicResponseExample } from "/components/dynamic-response-example.jsx";
### Body Parameters
<DynamicParamField body="customer_id" type="string" required>
The ID of the customer to attach the plans to.
</DynamicParamField>
<DynamicParamField body="entity_id" type="string">
The ID of the entity to attach the plans to.
</DynamicParamField>
<DynamicParamField body="plans" type="object[]" required>
The list of plans to attach to the customer.
<Expandable title="properties">
<DynamicParamField body="plan_id" type="string" required>
The ID of the plan to attach.
</DynamicParamField>
<DynamicParamField body="customize" type="object">
Customize the plan to attach. Can override the price or items.
<Expandable title="properties">
<DynamicParamField body="price" type="object | null">
Base price configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="amount" type="number" required>
Base price amount for the plan.
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval (e.g. 'month', 'year').
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="items" type="object[]">
Override the items in the plan.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to configure.
</DynamicParamField>
<DynamicParamField body="included" type="number">
Number of free units included. Balance resets to this each interval for consumable features.
</DynamicParamField>
<DynamicParamField body="unlimited" type="boolean">
If true, customer has unlimited access to this feature.
</DynamicParamField>
<DynamicParamField body="reset" type="object">
Reset configuration for consumable features. Omit for non-consumable features like seats.
<Expandable title="properties">
<DynamicParamField body="interval" type="'one_off' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals between resets. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="price" type="object">
Pricing for usage beyond included units. Omit for free features.
<Expandable title="properties">
<DynamicParamField body="amount" type="number">
Price per billing_units after included usage. Either 'amount' or 'tiers' is required.
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
<DynamicParamField body="billing_units" type="number">
Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200).
</DynamicParamField>
<DynamicParamField body="billing_method" type="'prepaid' | 'usage_based'" required>
'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
</DynamicParamField>
<DynamicParamField body="max_purchase" type="number">
Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="proration" type="object">
Proration settings for prepaid features. Controls mid-cycle quantity change billing.
<Expandable title="properties">
<DynamicParamField body="on_increase" type="'bill_immediately' | 'prorate_immediately' | 'prorate_next_cycle' | 'bill_next_cycle'" required>
Billing behavior when quantity increases mid-cycle.
</DynamicParamField>
<DynamicParamField body="on_decrease" type="'prorate' | 'prorate_immediately' | 'prorate_next_cycle' | 'none' | 'no_prorations'" required>
Credit behavior when quantity decreases mid-cycle.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="rollover" type="object">
Rollover config for unused units. If set, unused included units carry over.
<Expandable title="properties">
<DynamicParamField body="max" type="number">
Max rollover units. Omit for unlimited rollover.
</DynamicParamField>
<DynamicParamField body="expiry_duration_type" type="'month' | 'forever'" required>
When rolled over units expire.
</DynamicParamField>
<DynamicParamField body="expiry_duration_length" type="number">
Number of periods before expiry.
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="feature_quantities" type="object[]">
If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to set quantity for.
</DynamicParamField>
<DynamicParamField body="quantity" type="number">
The quantity of the feature.
</DynamicParamField>
<DynamicParamField body="adjustable" type="boolean">
Whether the customer can adjust the quantity.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="version" type="number">
The version of the plan to attach.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="free_trial" type="object | null">
Free trial configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="duration_length" type="number" required>
Number of duration_type periods the trial lasts.
</DynamicParamField>
<DynamicParamField body="duration_type" type="'day' | 'month' | 'year'">
Unit of time for the trial ('day', 'month', 'year').
</DynamicParamField>
<DynamicParamField body="card_required" type="boolean">
If true, payment method required to start trial. Customer is charged after trial ends.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="invoice_mode" type="object">
Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately.
<Expandable title="properties">
<DynamicParamField body="enabled" type="boolean" required>
When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method.
</DynamicParamField>
<DynamicParamField body="enable_plan_immediately" type="boolean">
If true, enables the plan immediately even though the invoice is not paid yet.
</DynamicParamField>
<DynamicParamField body="finalize" type="boolean">
If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="discounts" type="object[]">
List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code.
<Expandable title="properties">
<DynamicParamField body="reward_id" type="string">
The ID of the reward to apply as a discount.
</DynamicParamField>
<DynamicParamField body="promotion_code" type="string">
The promotion code to apply as a discount.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="success_url" type="string">
URL to redirect to after successful checkout.
</DynamicParamField>
<DynamicParamField body="checkout_session_params" type="object">
Additional parameters to pass into the creation of the Stripe checkout session.
</DynamicParamField>
<DynamicParamField body="redirect_mode" type="'always' | 'if_required' | 'never'">
Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects.
</DynamicParamField>
<DynamicParamField body="new_billing_subscription" type="boolean">
Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
</DynamicParamField>
<DynamicParamField body="customer_data" type="object">
Customer details to set when creating a customer
<Expandable title="properties">
<DynamicParamField body="name" type="string | null">
Customer's name
</DynamicParamField>
<DynamicParamField body="email" type="string | null">
Customer's email address
</DynamicParamField>
<DynamicParamField body="fingerprint" type="string | null">
Unique identifier (eg, serial number) to detect duplicate customers and prevent free trial abuse
</DynamicParamField>
<DynamicParamField body="metadata" type="object | null">
Additional metadata for the customer
</DynamicParamField>
<DynamicParamField body="stripe_id" type="string | null">
Stripe customer ID if you already have one
</DynamicParamField>
<DynamicParamField body="create_in_stripe" type="boolean">
Whether to create the customer in Stripe
</DynamicParamField>
<DynamicParamField body="auto_enable_plan_id" type="string">
The ID of the free plan to auto-enable for the customer
</DynamicParamField>
<DynamicParamField body="send_email_receipts" type="boolean">
Whether to send email receipts to this customer
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="entity_data" type="object">
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The feature ID that this entity is associated with
</DynamicParamField>
<DynamicParamField body="name" type="string">
Name of the entity
</DynamicParamField>
</Expandable>
</DynamicParamField>
### Response
<DynamicResponseField name="customer_id" type="string">
The ID of the customer.
</DynamicResponseField>
<DynamicResponseField name="entity_id" type="string">
The ID of the entity, if the plan was attached to an entity.
</DynamicResponseField>
<DynamicResponseField name="invoice" type="object">
Invoice details if an invoice was created. Only present when a charge was made.
<Expandable title="properties">
<DynamicResponseField name="status" type="string | null">
The status of the invoice (e.g., 'paid', 'open', 'draft').
</DynamicResponseField>
<DynamicResponseField name="stripe_id" type="string">
The Stripe invoice ID.
</DynamicResponseField>
<DynamicResponseField name="total" type="number">
The total amount of the invoice in cents.
</DynamicResponseField>
<DynamicResponseField name="currency" type="string">
The three-letter ISO currency code (e.g., 'usd').
</DynamicResponseField>
<DynamicResponseField name="hosted_invoice_url" type="string | null">
URL to the hosted invoice page where the customer can view and pay the invoice.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="payment_url" type="string | null">
URL to redirect the customer to complete payment. Null if no payment action is required.
</DynamicResponseField>
<DynamicResponseField name="required_action" type="object">
Details about any action required to complete the payment. Present when the payment could not be processed automatically.
<Expandable title="properties">
<DynamicResponseField name="code" type="'3ds_required' | 'payment_method_required' | 'payment_failed'">
The type of action required to complete the payment.
</DynamicResponseField>
<DynamicResponseField name="reason" type="string">
A human-readable explanation of why this action is required.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<ResponseExample>
```json 200
{
"customer_id": "cus_123",
"invoice": {
"status": "paid",
"stripe_id": "in_1234",
"total": 4900,
"currency": "usd",
"hosted_invoice_url": "https://invoice.stripe.com/..."
},
"payment_url": null
}
```
</ResponseExample>

View File

@@ -101,15 +101,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
@@ -237,6 +241,10 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled.
</DynamicParamField>
<DynamicParamField body="checkout_session_params" type="object">
Additional parameters to pass into the creation of the Stripe checkout session.
</DynamicParamField>
### Response

View File

@@ -0,0 +1,379 @@
---
title: "Preview Multi Attach"
openapi: "openapi POST /v1/billing.preview_multi_attach"
---
import { DynamicParamField } from "/components/dynamic-param-field.jsx";
import { DynamicResponseField } from "/components/dynamic-response-field.jsx";
import { DynamicResponseExample } from "/components/dynamic-response-example.jsx";
### Body Parameters
<DynamicParamField body="customer_id" type="string" required>
The ID of the customer to attach the plans to.
</DynamicParamField>
<DynamicParamField body="entity_id" type="string">
The ID of the entity to attach the plans to.
</DynamicParamField>
<DynamicParamField body="plans" type="object[]" required>
The list of plans to attach to the customer.
<Expandable title="properties">
<DynamicParamField body="plan_id" type="string" required>
The ID of the plan to attach.
</DynamicParamField>
<DynamicParamField body="customize" type="object">
Customize the plan to attach. Can override the price or items.
<Expandable title="properties">
<DynamicParamField body="price" type="object | null">
Base price configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="amount" type="number" required>
Base price amount for the plan.
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval (e.g. 'month', 'year').
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="items" type="object[]">
Override the items in the plan.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to configure.
</DynamicParamField>
<DynamicParamField body="included" type="number">
Number of free units included. Balance resets to this each interval for consumable features.
</DynamicParamField>
<DynamicParamField body="unlimited" type="boolean">
If true, customer has unlimited access to this feature.
</DynamicParamField>
<DynamicParamField body="reset" type="object">
Reset configuration for consumable features. Omit for non-consumable features like seats.
<Expandable title="properties">
<DynamicParamField body="interval" type="'one_off' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals between resets. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="price" type="object">
Pricing for usage beyond included units. Omit for free features.
<Expandable title="properties">
<DynamicParamField body="amount" type="number">
Price per billing_units after included usage. Either 'amount' or 'tiers' is required.
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
<DynamicParamField body="billing_units" type="number">
Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200).
</DynamicParamField>
<DynamicParamField body="billing_method" type="'prepaid' | 'usage_based'" required>
'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
</DynamicParamField>
<DynamicParamField body="max_purchase" type="number">
Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="proration" type="object">
Proration settings for prepaid features. Controls mid-cycle quantity change billing.
<Expandable title="properties">
<DynamicParamField body="on_increase" type="'bill_immediately' | 'prorate_immediately' | 'prorate_next_cycle' | 'bill_next_cycle'" required>
Billing behavior when quantity increases mid-cycle.
</DynamicParamField>
<DynamicParamField body="on_decrease" type="'prorate' | 'prorate_immediately' | 'prorate_next_cycle' | 'none' | 'no_prorations'" required>
Credit behavior when quantity decreases mid-cycle.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="rollover" type="object">
Rollover config for unused units. If set, unused included units carry over.
<Expandable title="properties">
<DynamicParamField body="max" type="number">
Max rollover units. Omit for unlimited rollover.
</DynamicParamField>
<DynamicParamField body="expiry_duration_type" type="'month' | 'forever'" required>
When rolled over units expire.
</DynamicParamField>
<DynamicParamField body="expiry_duration_length" type="number">
Number of periods before expiry.
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="feature_quantities" type="object[]">
If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to set quantity for.
</DynamicParamField>
<DynamicParamField body="quantity" type="number">
The quantity of the feature.
</DynamicParamField>
<DynamicParamField body="adjustable" type="boolean">
Whether the customer can adjust the quantity.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="version" type="number">
The version of the plan to attach.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="free_trial" type="object | null">
Free trial configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="duration_length" type="number" required>
Number of duration_type periods the trial lasts.
</DynamicParamField>
<DynamicParamField body="duration_type" type="'day' | 'month' | 'year'">
Unit of time for the trial ('day', 'month', 'year').
</DynamicParamField>
<DynamicParamField body="card_required" type="boolean">
If true, payment method required to start trial. Customer is charged after trial ends.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="invoice_mode" type="object">
Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately.
<Expandable title="properties">
<DynamicParamField body="enabled" type="boolean" required>
When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method.
</DynamicParamField>
<DynamicParamField body="enable_plan_immediately" type="boolean">
If true, enables the plan immediately even though the invoice is not paid yet.
</DynamicParamField>
<DynamicParamField body="finalize" type="boolean">
If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="discounts" type="object[]">
List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code.
<Expandable title="properties">
<DynamicParamField body="reward_id" type="string">
The ID of the reward to apply as a discount.
</DynamicParamField>
<DynamicParamField body="promotion_code" type="string">
The promotion code to apply as a discount.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="success_url" type="string">
URL to redirect to after successful checkout.
</DynamicParamField>
<DynamicParamField body="checkout_session_params" type="object">
Additional parameters to pass into the creation of the Stripe checkout session.
</DynamicParamField>
<DynamicParamField body="redirect_mode" type="'always' | 'if_required' | 'never'">
Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects.
</DynamicParamField>
<DynamicParamField body="new_billing_subscription" type="boolean">
Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one.
</DynamicParamField>
<DynamicParamField body="customer_data" type="object">
Customer details to set when creating a customer
<Expandable title="properties">
<DynamicParamField body="name" type="string | null">
Customer's name
</DynamicParamField>
<DynamicParamField body="email" type="string | null">
Customer's email address
</DynamicParamField>
<DynamicParamField body="fingerprint" type="string | null">
Unique identifier (eg, serial number) to detect duplicate customers and prevent free trial abuse
</DynamicParamField>
<DynamicParamField body="metadata" type="object | null">
Additional metadata for the customer
</DynamicParamField>
<DynamicParamField body="stripe_id" type="string | null">
Stripe customer ID if you already have one
</DynamicParamField>
<DynamicParamField body="create_in_stripe" type="boolean">
Whether to create the customer in Stripe
</DynamicParamField>
<DynamicParamField body="auto_enable_plan_id" type="string">
The ID of the free plan to auto-enable for the customer
</DynamicParamField>
<DynamicParamField body="send_email_receipts" type="boolean">
Whether to send email receipts to this customer
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="entity_data" type="object">
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The feature ID that this entity is associated with
</DynamicParamField>
<DynamicParamField body="name" type="string">
Name of the entity
</DynamicParamField>
</Expandable>
</DynamicParamField>
### Response
<DynamicResponseField name="customer_id" type="string">
The ID of the customer.
</DynamicResponseField>
<DynamicResponseField name="line_items" type="object[]">
List of line items for the current billing period.
<Expandable title="properties">
<DynamicResponseField name="title" type="string">
The title of the line item.
</DynamicResponseField>
<DynamicResponseField name="description" type="string">
A detailed description of the line item.
</DynamicResponseField>
<DynamicResponseField name="amount" type="number">
The amount in cents for this line item.
</DynamicResponseField>
<DynamicResponseField name="discounts" type="object[]">
List of discounts applied to this line item.
<Expandable title="properties">
<DynamicResponseField name="amountOff" type="number" />
<DynamicResponseField name="percentOff" type="number" />
<DynamicResponseField name="stripeCouponId" type="string" />
<DynamicResponseField name="couponName" type="string" />
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="total" type="number">
The total amount in cents for the current billing period.
</DynamicResponseField>
<DynamicResponseField name="currency" type="string">
The three-letter ISO currency code (e.g., 'usd').
</DynamicResponseField>
<DynamicResponseField name="next_cycle" type="object">
Preview of the next billing cycle, if applicable. This shows what the customer will be charged in subsequent cycles.
<Expandable title="properties">
<DynamicResponseField name="starts_at" type="number">
Unix timestamp (milliseconds) when the next billing cycle starts.
</DynamicResponseField>
<DynamicResponseField name="total" type="number">
The total amount in cents for the next cycle.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<ResponseExample>
```json 200
{
"customerId": "charles",
"lineItems": [
{
"title": "Pro seed",
"description": "Pro seed - Base Price (from 18 Feb 2026 to 18 Mar 2026)",
"amount": 20,
"discounts": []
}
],
"total": 20,
"currency": "usd"
}
```
</ResponseExample>

View File

@@ -101,15 +101,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>

View File

@@ -10,53 +10,213 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
### Body Parameters
<DynamicParamField body="customer_id" type="string" required>
The ID of the customer
The ID of the customer to attach the plan to.
</DynamicParamField>
<DynamicParamField body="success_url" type="string">
URL to redirect to after successful payment setup. Must start with either http:// or https://
<DynamicParamField body="entity_id" type="string">
The ID of the entity to attach the plan to.
</DynamicParamField>
<DynamicParamField body="customer_data" type="object">
Customer details to set when creating a customer
<DynamicParamField body="plan_id" type="string">
If specified, the plan will be attached to the customer after setup.
</DynamicParamField>
<DynamicParamField body="feature_quantities" type="object[]">
If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan.
<Expandable title="properties">
<DynamicParamField body="name" type="string | null">
Customer's name
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to set quantity for.
</DynamicParamField>
<DynamicParamField body="email" type="string | null">
Customer's email address
<DynamicParamField body="quantity" type="number">
The quantity of the feature.
</DynamicParamField>
<DynamicParamField body="fingerprint" type="string | null">
Unique identifier (eg, serial number) to detect duplicate customers and prevent free trial abuse
</DynamicParamField>
<DynamicParamField body="metadata" type="object | null">
Additional metadata for the customer
</DynamicParamField>
<DynamicParamField body="stripe_id" type="string | null">
Stripe customer ID if you already have one
</DynamicParamField>
<DynamicParamField body="create_in_stripe" type="boolean">
Whether to create the customer in Stripe
</DynamicParamField>
<DynamicParamField body="auto_enable_plan_id" type="string">
The ID of the free plan to auto-enable for the customer
</DynamicParamField>
<DynamicParamField body="send_email_receipts" type="boolean">
Whether to send email receipts to this customer
<DynamicParamField body="adjustable" type="boolean">
Whether the customer can adjust the quantity.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="version" type="number">
The version of the plan to attach.
</DynamicParamField>
<DynamicParamField body="customize" type="object">
Customize the plan to attach. Can override the price, items, free trial, or a combination.
<Expandable title="properties">
<DynamicParamField body="price" type="object | null">
Base price configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="amount" type="number" required>
Base price amount for the plan.
</DynamicParamField>
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval (e.g. 'month', 'year').
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="items" type="object[]">
Override the items in the plan.
<Expandable title="properties">
<DynamicParamField body="feature_id" type="string" required>
The ID of the feature to configure.
</DynamicParamField>
<DynamicParamField body="included" type="number">
Number of free units included. Balance resets to this each interval for consumable features.
</DynamicParamField>
<DynamicParamField body="unlimited" type="boolean">
If true, customer has unlimited access to this feature.
</DynamicParamField>
<DynamicParamField body="reset" type="object">
Reset configuration for consumable features. Omit for non-consumable features like seats.
<Expandable title="properties">
<DynamicParamField body="interval" type="'one_off' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals between resets. Defaults to 1.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="price" type="object">
Pricing for usage beyond included units. Omit for free features.
<Expandable title="properties">
<DynamicParamField body="amount" type="number">
Price per billing_units after included usage. Either 'amount' or 'tiers' is required.
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
<DynamicParamField body="interval_count" type="number">
Number of intervals per billing cycle. Defaults to 1.
</DynamicParamField>
<DynamicParamField body="billing_units" type="number">
Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200).
</DynamicParamField>
<DynamicParamField body="billing_method" type="'prepaid' | 'usage_based'" required>
'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
</DynamicParamField>
<DynamicParamField body="max_purchase" type="number">
Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="proration" type="object">
Proration settings for prepaid features. Controls mid-cycle quantity change billing.
<Expandable title="properties">
<DynamicParamField body="on_increase" type="'bill_immediately' | 'prorate_immediately' | 'prorate_next_cycle' | 'bill_next_cycle'" required>
Billing behavior when quantity increases mid-cycle.
</DynamicParamField>
<DynamicParamField body="on_decrease" type="'prorate' | 'prorate_immediately' | 'prorate_next_cycle' | 'none' | 'no_prorations'" required>
Credit behavior when quantity decreases mid-cycle.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="rollover" type="object">
Rollover config for unused units. If set, unused included units carry over.
<Expandable title="properties">
<DynamicParamField body="max" type="number">
Max rollover units. Omit for unlimited rollover.
</DynamicParamField>
<DynamicParamField body="expiry_duration_type" type="'month' | 'forever'" required>
When rolled over units expire.
</DynamicParamField>
<DynamicParamField body="expiry_duration_length" type="number">
Number of periods before expiry.
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="free_trial" type="object | null">
Free trial configuration for a plan.
<Expandable title="properties">
<DynamicParamField body="duration_length" type="number" required>
Number of duration_type periods the trial lasts.
</DynamicParamField>
<DynamicParamField body="duration_type" type="'day' | 'month' | 'year'">
Unit of time for the trial ('day', 'month', 'year').
</DynamicParamField>
<DynamicParamField body="card_required" type="boolean">
If true, payment method required to start trial. Customer is charged after trial ends.
</DynamicParamField>
</Expandable>
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="proration_behavior" type="'prorate_immediately' | 'none'">
How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges.
</DynamicParamField>
<DynamicParamField body="discounts" type="object[]">
List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code.
<Expandable title="properties">
<DynamicParamField body="reward_id" type="string">
The ID of the reward to apply as a discount.
</DynamicParamField>
<DynamicParamField body="promotion_code" type="string">
The promotion code to apply as a discount.
</DynamicParamField>
</Expandable>
</DynamicParamField>
<DynamicParamField body="success_url" type="string">
URL to redirect to after successful checkout.
</DynamicParamField>
<DynamicParamField body="checkout_session_params" type="object">
Additional parameters for the checkout session
Additional parameters to pass into the creation of the Stripe checkout session.
</DynamicParamField>
@@ -66,8 +226,12 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
The ID of the customer
</DynamicResponseField>
<DynamicResponseField name="entity_id" type="string">
The ID of the entity the plan (if specified) will be attached to after setup.
</DynamicResponseField>
<DynamicResponseField name="url" type="string">
URL to the payment setup page
URL to redirect the customer to setup their payment.
</DynamicResponseField>
@@ -75,7 +239,7 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
```json 200
{
"customer_id": "cus_123",
"payment_url": "https://checkout.stripe.com/..."
"url": "https://checkout.stripe.com/..."
}
```
</ResponseExample>

View File

@@ -244,9 +244,15 @@ const { allowed } = await autumn.check({
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>
@@ -390,9 +396,17 @@ const { allowed } = await autumn.check({
The price of the product item for this tier.
</DynamicResponseField>
<DynamicResponseField name="flat_amount" type="number | null">
A flat fee charged for this tier, in addition to the per-unit amount.
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier). Defaults to graduated.
</DynamicResponseField>
<DynamicResponseField name="usage_model" type="'prepaid' | 'pay_per_use'">
Whether the feature should be prepaid upfront or billed for how much they use end of billing period.
</DynamicResponseField>

View File

@@ -243,9 +243,15 @@ await autumn.track({
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>
@@ -441,9 +447,15 @@ await autumn.track({
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>

View File

@@ -245,15 +245,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -346,6 +350,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -553,15 +570,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -654,6 +675,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -832,9 +866,15 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>

View File

@@ -230,15 +230,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -331,6 +335,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -538,15 +555,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -639,6 +660,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -817,9 +851,15 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>

View File

@@ -233,15 +233,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -334,6 +338,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -541,15 +558,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -642,6 +663,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -820,9 +854,15 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>

View File

@@ -244,15 +244,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -345,6 +349,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -551,15 +568,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -652,6 +673,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -829,9 +863,15 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>

View File

@@ -198,15 +198,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -299,6 +303,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -505,15 +522,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -606,6 +627,19 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
@@ -783,9 +817,15 @@ import { DynamicResponseExample } from "/components/dynamic-response-example.jsx
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'">
How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
</DynamicResponseField>
<DynamicResponseField name="billing_units" type="number">
The number of units per billing increment (eg. $9 / 250 units).
</DynamicResponseField>

View File

@@ -219,15 +219,19 @@ await autumn.plans.create({
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
@@ -454,15 +458,19 @@ await autumn.plans.create({
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -555,6 +563,19 @@ await autumn.plans.create({
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<ResponseExample>
```json 200

View File

@@ -188,15 +188,19 @@ const plan = await autumn.plans.get({
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -289,6 +293,19 @@ const plan = await autumn.plans.get({
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<ResponseExample>
```json 200

View File

@@ -205,15 +205,19 @@ const plans = await autumn.plans.list({
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -306,6 +310,19 @@ const plans = await autumn.plans.list({
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
</Expandable>
</DynamicResponseField>

View File

@@ -146,15 +146,19 @@ await autumn.plans.update({
</DynamicParamField>
<DynamicParamField body="tiers" type="object[]">
Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
Tiered pricing. Either 'amount' or 'tiers' is required.
<Expandable title="properties">
<DynamicParamField body="to" type="number" required />
<DynamicParamField body="amount" type="number" required />
<DynamicParamField body="flat_amount" type="number | null" />
</Expandable>
</DynamicParamField>
<DynamicParamField body="tier_behavior" type="'graduated' | 'volume'" />
<DynamicParamField body="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'" required>
Billing interval. For consumable features, should match reset.interval.
</DynamicParamField>
@@ -389,15 +393,19 @@ await autumn.plans.update({
</DynamicResponseField>
<DynamicResponseField name="tiers" type="object[]">
Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
<Expandable title="properties">
<DynamicResponseField name="to" type="number" />
<DynamicResponseField name="amount" type="number" />
<DynamicResponseField name="flat_amount" type="number | null" />
</Expandable>
</DynamicResponseField>
<DynamicResponseField name="tier_behavior" type="'graduated' | 'volume'" />
<DynamicResponseField name="interval" type="'one_off' | 'week' | 'month' | 'quarter' | 'semi_annual' | 'year'">
Billing interval for this price. For consumable features, should match reset.interval.
</DynamicResponseField>
@@ -490,6 +498,19 @@ await autumn.plans.update({
If this is a variant, the ID of the base plan it was created from.
</DynamicResponseField>
<DynamicResponseField name="customer_eligibility" type="object">
<Expandable title="properties">
<DynamicResponseField name="trial_available" type="boolean">
Whether a free trial is available for this customer.
</DynamicResponseField>
<DynamicResponseField name="scenario" type="'scheduled' | 'active' | 'new' | 'renew' | 'upgrade' | 'downgrade' | 'cancel' | 'expired' | 'past_due'">
The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
</DynamicResponseField>
</Expandable>
</DynamicResponseField>
<ResponseExample>
```json 200

File diff suppressed because it is too large Load Diff

View File

@@ -129,12 +129,14 @@
{
"group": "Billing",
"pages": [
"api-reference/billing/billingAttach",
"api-reference/billing/attach",
"api-reference/billing/billingUpdate",
"api-reference/billing/previewAttach",
"api-reference/billing/previewUpdate",
"api-reference/billing/openCustomerPortal",
"api-reference/billing/setupPayment"
"api-reference/billing/setupPayment",
"api-reference/billing/previewMultiAttach",
"api-reference/billing/multiAttach"
]
},
{

View File

@@ -292,7 +292,7 @@ curl -X POST 'https://api.useautumn.com/v1/billing.open_customer_portal' \
### Usage history chart
Autumn replicates usage data to Clickhouse for aggregate time series queries. Pass the response to a charting library like Recharts.
Autumn provides aggregate time series queries for usage data. Pass the response to a charting library like Recharts.
<CodeGroup>

View File

@@ -3,7 +3,7 @@
"private": true,
"scripts": {
"pull": "bun scripts/pull.ts",
"dev": "cd mintlify && mint dev --port 3003",
"dev": "cd mintlify && bun x mint dev --port 3003",
"build": "cd mintlify && mint build",
"start": "cd mintlify && mint dev"
},

View File

@@ -2,7 +2,9 @@
import type {
ClientAttachParams,
ClientMultiAttachParams,
ClientOpenCustomerPortalParams,
ClientSetupPaymentParams,
} from "autumn-js/react";
import { useCustomer } from "autumn-js/react";
import { useId, useState } from "react";
@@ -13,7 +15,12 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
type ActionTab = "attach" | "check" | "openCustomerPortal";
type ActionTab =
| "attach"
| "multiAttach"
| "check"
| "setupPayment"
| "openCustomerPortal";
type LastActionState = {
name: string;
@@ -46,10 +53,18 @@ const toErrorPayload = ({ error }: { error: unknown }) => {
};
export default function UseAutumnScenarioPage() {
const { isLoading, error, refetch, attach, check, openCustomerPortal } =
useCustomer({
errorOnNotFound: false,
});
const {
isLoading,
error,
refetch,
attach,
multiAttach,
check,
setupPayment,
openCustomerPortal,
} = useCustomer({
errorOnNotFound: false,
});
const [lastUpdatedAt, setLastUpdatedAt] = useState<string | null>(null);
const [isRunning, setIsRunning] = useState(false);
@@ -64,12 +79,18 @@ export default function UseAutumnScenarioPage() {
const [requiredBalance, setRequiredBalance] = useState("");
const [openInNewTab, setOpenInNewTab] = useState(false);
const [portalReturnUrl, setPortalReturnUrl] = useState("");
const [multiAttachPlanIds, setMultiAttachPlanIds] = useState("");
const [setupPaymentSuccessUrl, setSetupPaymentSuccessUrl] = useState("");
const [setupPaymentPlanId, setSetupPaymentPlanId] = useState("");
// Form element IDs
const planIdInputId = useId();
const featureIdInputId = useId();
const requiredBalanceInputId = useId();
const portalReturnUrlInputId = useId();
const multiAttachPlanIdsInputId = useId();
const setupPaymentSuccessUrlInputId = useId();
const setupPaymentPlanIdInputId = useId();
const runAction = async ({
name,
@@ -137,6 +158,35 @@ export default function UseAutumnScenarioPage() {
});
};
const handleMultiAttach = () => {
if (!multiAttachPlanIds) return;
const plans = multiAttachPlanIds
.split(",")
.map((id) => ({ planId: id.trim() }));
const params: ClientMultiAttachParams = {
plans,
openInNewTab,
};
runAction({
name: "multiAttach",
params,
execute: () => multiAttach(params),
});
};
const handleSetupPayment = () => {
const params: ClientSetupPaymentParams = {
planId: setupPaymentPlanId || undefined,
successUrl: setupPaymentSuccessUrl || undefined,
openInNewTab,
};
runAction({
name: "setupPayment",
params,
execute: () => setupPayment(params),
});
};
const handleOpenCustomerPortal = () => {
const params: ClientOpenCustomerPortalParams = {
returnUrl: portalReturnUrl || undefined,
@@ -180,6 +230,17 @@ export default function UseAutumnScenarioPage() {
>
Attach
</button>
<button
type="button"
onClick={() => setActiveTab("multiAttach")}
className={`-mb-px border-b-2 px-3 py-1.5 text-sm font-medium transition-colors ${
activeTab === "multiAttach"
? "border-zinc-900 text-zinc-900"
: "border-transparent text-zinc-500 hover:text-zinc-700"
}`}
>
Multi Attach
</button>
<button
type="button"
onClick={() => setActiveTab("check")}
@@ -191,6 +252,17 @@ export default function UseAutumnScenarioPage() {
>
Check
</button>
<button
type="button"
onClick={() => setActiveTab("setupPayment")}
className={`-mb-px border-b-2 px-3 py-1.5 text-sm font-medium transition-colors ${
activeTab === "setupPayment"
? "border-zinc-900 text-zinc-900"
: "border-transparent text-zinc-500 hover:text-zinc-700"
}`}
>
Setup Payment
</button>
<button
type="button"
onClick={() => setActiveTab("openCustomerPortal")}
@@ -281,6 +353,92 @@ export default function UseAutumnScenarioPage() {
</div>
)}
{activeTab === "multiAttach" && (
<div className="space-y-3">
<div className="space-y-1.5">
<Label
htmlFor={multiAttachPlanIdsInputId}
className="text-xs text-zinc-500"
>
Plan IDs (comma-separated)
</Label>
<Input
id={multiAttachPlanIdsInputId}
placeholder="pro_plan, addon_seats"
value={multiAttachPlanIds}
onChange={(e) => setMultiAttachPlanIds(e.target.value)}
className="h-8 text-sm"
/>
</div>
<label className="flex items-center gap-2 text-sm text-zinc-600">
<input
type="checkbox"
checked={openInNewTab}
onChange={(e) => setOpenInNewTab(e.target.checked)}
className="rounded border-zinc-300"
/>
Open in new tab
</label>
<Button
size="sm"
disabled={isRunning || !multiAttachPlanIds}
onClick={handleMultiAttach}
>
{isRunning ? "Running..." : "Multi Attach"}
</Button>
</div>
)}
{activeTab === "setupPayment" && (
<div className="space-y-3">
<div className="space-y-1.5">
<Label
htmlFor={setupPaymentPlanIdInputId}
className="text-xs text-zinc-500"
>
Plan ID (optional)
</Label>
<Input
id={setupPaymentPlanIdInputId}
placeholder="Attach plan after setup"
value={setupPaymentPlanId}
onChange={(e) => setSetupPaymentPlanId(e.target.value)}
className="h-8 text-sm"
/>
</div>
<div className="space-y-1.5">
<Label
htmlFor={setupPaymentSuccessUrlInputId}
className="text-xs text-zinc-500"
>
Success URL (optional)
</Label>
<Input
id={setupPaymentSuccessUrlInputId}
placeholder="https://app.example.com/billing"
value={setupPaymentSuccessUrl}
onChange={(e) => setSetupPaymentSuccessUrl(e.target.value)}
className="h-8 text-sm"
/>
<p className="text-[11px] leading-tight text-zinc-500">
Defaults to the current page URL when left empty.
</p>
</div>
<label className="flex items-center gap-2 text-sm text-zinc-600">
<input
type="checkbox"
checked={openInNewTab}
onChange={(e) => setOpenInNewTab(e.target.checked)}
className="rounded border-zinc-300"
/>
Open in new tab
</label>
<Button size="sm" disabled={isRunning} onClick={handleSetupPayment}>
{isRunning ? "Running..." : "Setup Payment"}
</Button>
</div>
)}
{activeTab === "openCustomerPortal" && (
<div className="space-y-3">
<div className="space-y-1.5">

View File

@@ -1,7 +1,16 @@
import path from "node:path";
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
transpilePackages: ["autumn-js"],
turbopack: {
resolveAlias: {
"@useautumn/sdk": path.resolve(
import.meta.dirname,
"../../packages/sdk/dist/esm/index.js",
),
},
},
};
export default nextConfig;

View File

@@ -179,7 +179,6 @@
"version": "1.0.0",
"dependencies": {
"@autumn/shared": "workspace:*",
"@clickhouse/client": "catalog:",
"chalk": "^5.3.0",
"dotenv": "^16.5.0",
"drizzle-orm": "catalog:",

View File

@@ -93,6 +93,37 @@ actions:
res = autumn.billing.attach(customer_id="cus_123", plan_id="pro_plan")
# Handle response
print(res)
- target: $["paths"]["/v1/billing.multi_attach"]["post"]
update:
x-codeSamples:
- lang: python
label: Python (SDK)
source: |-
from autumn_sdk import Autumn
with Autumn(
x_api_version="2.1",
secret_key="<YOUR_BEARER_TOKEN_HERE>",
) as autumn:
res = autumn.billing.multi_attach(customer_id="cus_123", plans=[
{
"plan_id": "pro_plan",
},
{
"plan_id": "addon_seats",
"feature_quantities": [
{
"feature_id": "seats",
"quantity": 5,
},
],
},
], redirect_mode="if_required")
# Handle response
print(res)
- target: $["paths"]["/v1/billing.open_customer_portal"]["post"]
@@ -129,6 +160,37 @@ actions:
res = autumn.billing.preview_attach(customer_id="cus_123", plan_id="pro_plan")
# Handle response
print(res)
- target: $["paths"]["/v1/billing.preview_multi_attach"]["post"]
update:
x-codeSamples:
- lang: python
label: Python (SDK)
source: |-
from autumn_sdk import Autumn
with Autumn(
x_api_version="2.1",
secret_key="<YOUR_BEARER_TOKEN_HERE>",
) as autumn:
res = autumn.billing.preview_multi_attach(customer_id="cus_123", plans=[
{
"plan_id": "pro_plan",
},
{
"plan_id": "addon_seats",
"feature_quantities": [
{
"feature_id": "seats",
"quantity": 5,
},
],
},
], redirect_mode="if_required")
# Handle response
print(res)
- target: $["paths"]["/v1/billing.preview_update"]["post"]

File diff suppressed because it is too large Load Diff

View File

@@ -15,8 +15,8 @@ generation:
sharedErrorComponentsApr2025: true
sharedNestedComponentsJan2026: true
auth:
oAuth2ClientCredentialsEnabled: true
oAuth2PasswordEnabled: true
oAuth2ClientCredentialsEnabled: false
oAuth2PasswordEnabled: false
hoistGlobalSecurity: true
inferSSEOverload: true
sdkHooksConfigAccess: true

View File

@@ -217,9 +217,15 @@ Use this after an action happens to decrement usage, or send a negative value to
* [attach](docs/sdks/billing/README.md#attach) - Attaches a plan to a customer. Handles new subscriptions, upgrades and downgrades.
Use this endpoint to subscribe a customer to a plan, upgrade/downgrade between plans, or add an add-on product.
* [multi_attach](docs/sdks/billing/README.md#multi_attach) - Attaches multiple plans to a customer in a single request. Creates a single Stripe subscription with all plans consolidated.
Use this endpoint when you need to subscribe a customer to multiple plans at once, such as a base plan plus add-ons, or to create a bundle of products.
* [preview_attach](docs/sdks/billing/README.md#preview_attach) - Previews the billing changes that would occur when attaching a plan, without actually making any changes.
Use this endpoint to show customers what they will be charged before confirming a subscription change.
* [preview_multi_attach](docs/sdks/billing/README.md#preview_multi_attach) - Previews the billing changes that would occur when attaching multiple plans, without actually making any changes.
Use this endpoint to show customers what they will be charged before confirming a multi-plan subscription.
* [update](docs/sdks/billing/README.md#update) - Updates an existing subscription. Use to modify feature quantities, cancel, or change plan configuration.
Use this endpoint to update prepaid quantities, cancel a subscription (immediately or at end of cycle), or modify subscription settings.

View File

@@ -2,4 +2,3 @@
from .sdkhooks import *
from .types import *
from .registration import *

View File

@@ -11,7 +11,6 @@ from .types import (
AfterErrorHook,
Hooks,
)
from .registration import init_hooks
from typing import List, Optional, Tuple
from autumn_sdk.sdkconfiguration import SDKConfiguration
@@ -22,7 +21,6 @@ class SDKHooks(Hooks):
self.before_request_hooks: List[BeforeRequestHook] = []
self.after_success_hooks: List[AfterSuccessHook] = []
self.after_error_hooks: List[AfterErrorHook] = []
init_hooks(self)
def register_sdk_init_hook(self, hook: SDKInitHook) -> None:
self.sdk_init_hooks.append(hook)

View File

@@ -237,6 +237,7 @@ class Balances(BaseSDK):
entity_id: Optional[str] = None,
remaining: Optional[float] = None,
add_to_balance: Optional[float] = None,
usage: Optional[float] = None,
interval: Optional[models.UpdateBalanceInterval] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
@@ -250,6 +251,7 @@ class Balances(BaseSDK):
:param entity_id: The ID of the entity for entity-scoped balances (e.g., per-seat limits).
:param remaining: Set the remaining balance to this exact value. Cannot be combined with add_to_balance.
:param add_to_balance: Add this amount to the current balance. Use negative values to subtract. Cannot be combined with current_balance.
:param usage: The usage amount to update. Cannot be combined with remaining or add_to_balance.
:param interval: Target a specific balance by its reset interval. Use when the customer has multiple balances for the same feature with different reset intervals.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -272,6 +274,7 @@ class Balances(BaseSDK):
entity_id=entity_id,
remaining=remaining,
add_to_balance=add_to_balance,
usage=usage,
interval=interval,
)
@@ -342,6 +345,7 @@ class Balances(BaseSDK):
entity_id: Optional[str] = None,
remaining: Optional[float] = None,
add_to_balance: Optional[float] = None,
usage: Optional[float] = None,
interval: Optional[models.UpdateBalanceInterval] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
@@ -355,6 +359,7 @@ class Balances(BaseSDK):
:param entity_id: The ID of the entity for entity-scoped balances (e.g., per-seat limits).
:param remaining: Set the remaining balance to this exact value. Cannot be combined with add_to_balance.
:param add_to_balance: Add this amount to the current balance. Use negative values to subtract. Cannot be combined with current_balance.
:param usage: The usage amount to update. Cannot be combined with remaining or add_to_balance.
:param interval: Target a specific balance by its reset interval. Use when the customer has multiple balances for the same feature with different reset intervals.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -377,6 +382,7 @@ class Balances(BaseSDK):
entity_id=entity_id,
remaining=remaining,
add_to_balance=add_to_balance,
usage=usage,
interval=interval,
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -12,15 +12,15 @@ from autumn_sdk.types import (
from autumn_sdk.utils import FieldMetadata, HeaderMetadata
import pydantic
from pydantic import model_serializer
from typing import List, Literal, Optional, Union
from typing import Any, Dict, List, Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
class BillingAttachGlobalsTypedDict(TypedDict):
class AttachGlobalsTypedDict(TypedDict):
x_api_version: NotRequired[str]
class BillingAttachGlobals(BaseModel):
class AttachGlobals(BaseModel):
x_api_version: Annotated[
Optional[str],
pydantic.Field(alias="x-api-version"),
@@ -44,7 +44,7 @@ class BillingAttachGlobals(BaseModel):
return m
class BillingAttachFeatureQuantityTypedDict(TypedDict):
class AttachFeatureQuantityTypedDict(TypedDict):
r"""Quantity configuration for a prepaid feature."""
feature_id: str
@@ -55,7 +55,7 @@ class BillingAttachFeatureQuantityTypedDict(TypedDict):
r"""Whether the customer can adjust the quantity."""
class BillingAttachFeatureQuantity(BaseModel):
class AttachFeatureQuantity(BaseModel):
r"""Quantity configuration for a prepaid feature."""
feature_id: str
@@ -84,7 +84,7 @@ class BillingAttachFeatureQuantity(BaseModel):
return m
BillingAttachPriceInterval = Literal[
AttachPriceInterval = Literal[
"one_off",
"week",
"month",
@@ -95,24 +95,24 @@ BillingAttachPriceInterval = Literal[
r"""Billing interval (e.g. 'month', 'year')."""
class BillingAttachBasePriceTypedDict(TypedDict):
class AttachBasePriceTypedDict(TypedDict):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: BillingAttachPriceInterval
interval: AttachPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
class BillingAttachBasePrice(BaseModel):
class AttachBasePrice(BaseModel):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: BillingAttachPriceInterval
interval: AttachPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: Optional[float] = None
@@ -135,7 +135,7 @@ class BillingAttachBasePrice(BaseModel):
return m
BillingAttachResetInterval = Literal[
AttachResetInterval = Literal[
"one_off",
"minute",
"hour",
@@ -149,19 +149,19 @@ BillingAttachResetInterval = Literal[
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
class BillingAttachResetTypedDict(TypedDict):
class AttachResetTypedDict(TypedDict):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: BillingAttachResetInterval
interval: AttachResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: NotRequired[float]
r"""Number of intervals between resets. Defaults to 1."""
class BillingAttachReset(BaseModel):
class AttachReset(BaseModel):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: BillingAttachResetInterval
interval: AttachResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: Optional[float] = None
@@ -184,24 +184,58 @@ class BillingAttachReset(BaseModel):
return m
BillingAttachToTypedDict = TypeAliasType("BillingAttachToTypedDict", Union[float, str])
AttachToTypedDict = TypeAliasType("AttachToTypedDict", Union[float, str])
BillingAttachTo = TypeAliasType("BillingAttachTo", Union[float, str])
AttachTo = TypeAliasType("AttachTo", Union[float, str])
class BillingAttachTierTypedDict(TypedDict):
to: BillingAttachToTypedDict
class AttachTierTypedDict(TypedDict):
to: AttachToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class BillingAttachTier(BaseModel):
to: BillingAttachTo
class AttachTier(BaseModel):
to: AttachTo
amount: float
flat_amount: OptionalNullable[float] = UNSET
BillingAttachItemPriceInterval = Literal[
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
AttachTierBehavior = Literal[
"graduated",
"volume",
]
AttachItemPriceInterval = Literal[
"one_off",
"week",
"month",
@@ -212,24 +246,25 @@ BillingAttachItemPriceInterval = Literal[
r"""Billing interval. For consumable features, should match reset.interval."""
BillingAttachBillingMethod = Literal[
AttachBillingMethod = Literal[
"prepaid",
"usage_based",
]
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
class BillingAttachPriceTypedDict(TypedDict):
class AttachPriceTypedDict(TypedDict):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: BillingAttachItemPriceInterval
interval: AttachItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: BillingAttachBillingMethod
billing_method: AttachBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[BillingAttachTierTypedDict]]
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[AttachTierTypedDict]]
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[AttachTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
@@ -238,20 +273,22 @@ class BillingAttachPriceTypedDict(TypedDict):
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
class BillingAttachPrice(BaseModel):
class AttachPrice(BaseModel):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: BillingAttachItemPriceInterval
interval: AttachItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: BillingAttachBillingMethod
billing_method: AttachBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: Optional[float] = None
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[BillingAttachTier]] = None
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[AttachTier]] = None
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[AttachTierBehavior] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -265,7 +302,14 @@ class BillingAttachPrice(BaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["amount", "tiers", "interval_count", "billing_units", "max_purchase"]
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}
@@ -281,7 +325,7 @@ class BillingAttachPrice(BaseModel):
return m
BillingAttachOnIncrease = Literal[
AttachOnIncrease = Literal[
"bill_immediately",
"prorate_immediately",
"prorate_next_cycle",
@@ -290,7 +334,7 @@ BillingAttachOnIncrease = Literal[
r"""Billing behavior when quantity increases mid-cycle."""
BillingAttachOnDecrease = Literal[
AttachOnDecrease = Literal[
"prorate",
"prorate_immediately",
"prorate_next_cycle",
@@ -300,36 +344,36 @@ BillingAttachOnDecrease = Literal[
r"""Credit behavior when quantity decreases mid-cycle."""
class BillingAttachProrationTypedDict(TypedDict):
class AttachProrationTypedDict(TypedDict):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: BillingAttachOnIncrease
on_increase: AttachOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: BillingAttachOnDecrease
on_decrease: AttachOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
class BillingAttachProration(BaseModel):
class AttachProration(BaseModel):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: BillingAttachOnIncrease
on_increase: AttachOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: BillingAttachOnDecrease
on_decrease: AttachOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
BillingAttachExpiryDurationType = Literal[
AttachExpiryDurationType = Literal[
"month",
"forever",
]
r"""When rolled over units expire."""
class BillingAttachRolloverTypedDict(TypedDict):
class AttachRolloverTypedDict(TypedDict):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: BillingAttachExpiryDurationType
expiry_duration_type: AttachExpiryDurationType
r"""When rolled over units expire."""
max: NotRequired[float]
r"""Max rollover units. Omit for unlimited rollover."""
@@ -337,10 +381,10 @@ class BillingAttachRolloverTypedDict(TypedDict):
r"""Number of periods before expiry."""
class BillingAttachRollover(BaseModel):
class AttachRollover(BaseModel):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: BillingAttachExpiryDurationType
expiry_duration_type: AttachExpiryDurationType
r"""When rolled over units expire."""
max: Optional[float] = None
@@ -366,7 +410,7 @@ class BillingAttachRollover(BaseModel):
return m
class BillingAttachPlanItemTypedDict(TypedDict):
class AttachPlanItemTypedDict(TypedDict):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
@@ -375,17 +419,17 @@ class BillingAttachPlanItemTypedDict(TypedDict):
r"""Number of free units included. Balance resets to this each interval for consumable features."""
unlimited: NotRequired[bool]
r"""If true, customer has unlimited access to this feature."""
reset: NotRequired[BillingAttachResetTypedDict]
reset: NotRequired[AttachResetTypedDict]
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: NotRequired[BillingAttachPriceTypedDict]
price: NotRequired[AttachPriceTypedDict]
r"""Pricing for usage beyond included units. Omit for free features."""
proration: NotRequired[BillingAttachProrationTypedDict]
proration: NotRequired[AttachProrationTypedDict]
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: NotRequired[BillingAttachRolloverTypedDict]
rollover: NotRequired[AttachRolloverTypedDict]
r"""Rollover config for unused units. If set, unused included units carry over."""
class BillingAttachPlanItem(BaseModel):
class AttachPlanItem(BaseModel):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
@@ -397,16 +441,16 @@ class BillingAttachPlanItem(BaseModel):
unlimited: Optional[bool] = None
r"""If true, customer has unlimited access to this feature."""
reset: Optional[BillingAttachReset] = None
reset: Optional[AttachReset] = None
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: Optional[BillingAttachPrice] = None
price: Optional[AttachPrice] = None
r"""Pricing for usage beyond included units. Omit for free features."""
proration: Optional[BillingAttachProration] = None
proration: Optional[AttachProration] = None
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: Optional[BillingAttachRollover] = None
rollover: Optional[AttachRollover] = None
r"""Rollover config for unused units. If set, unused included units carry over."""
@model_serializer(mode="wrap")
@@ -428,7 +472,7 @@ class BillingAttachPlanItem(BaseModel):
return m
BillingAttachDurationType = Literal[
AttachDurationType = Literal[
"day",
"month",
"year",
@@ -436,24 +480,24 @@ BillingAttachDurationType = Literal[
r"""Unit of time for the trial ('day', 'month', 'year')."""
class BillingAttachFreeTrialParamsTypedDict(TypedDict):
class AttachFreeTrialParamsTypedDict(TypedDict):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: NotRequired[BillingAttachDurationType]
duration_type: NotRequired[AttachDurationType]
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: NotRequired[bool]
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
class BillingAttachFreeTrialParams(BaseModel):
class AttachFreeTrialParams(BaseModel):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: Optional[BillingAttachDurationType] = "month"
duration_type: Optional[AttachDurationType] = "month"
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: Optional[bool] = True
@@ -476,27 +520,27 @@ class BillingAttachFreeTrialParams(BaseModel):
return m
class BillingAttachCustomizeTypedDict(TypedDict):
class AttachCustomizeTypedDict(TypedDict):
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
price: NotRequired[Nullable[BillingAttachBasePriceTypedDict]]
price: NotRequired[Nullable[AttachBasePriceTypedDict]]
r"""Override the base price of the plan. Pass null to remove the base price."""
items: NotRequired[List[BillingAttachPlanItemTypedDict]]
items: NotRequired[List[AttachPlanItemTypedDict]]
r"""Override the items in the plan."""
free_trial: NotRequired[Nullable[BillingAttachFreeTrialParamsTypedDict]]
free_trial: NotRequired[Nullable[AttachFreeTrialParamsTypedDict]]
r"""Override the plan's default free trial. Pass an object to set a custom trial, or null to remove the trial entirely."""
class BillingAttachCustomize(BaseModel):
class AttachCustomize(BaseModel):
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
price: OptionalNullable[BillingAttachBasePrice] = UNSET
price: OptionalNullable[AttachBasePrice] = UNSET
r"""Override the base price of the plan. Pass null to remove the base price."""
items: Optional[List[BillingAttachPlanItem]] = None
items: Optional[List[AttachPlanItem]] = None
r"""Override the items in the plan."""
free_trial: OptionalNullable[BillingAttachFreeTrialParams] = UNSET
free_trial: OptionalNullable[AttachFreeTrialParams] = UNSET
r"""Override the plan's default free trial. Pass an object to set a custom trial, or null to remove the trial entirely."""
@model_serializer(mode="wrap")
@@ -525,7 +569,7 @@ class BillingAttachCustomize(BaseModel):
return m
class BillingAttachInvoiceModeTypedDict(TypedDict):
class AttachInvoiceModeTypedDict(TypedDict):
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. This uses Stripe's send_invoice collection method."""
enabled: bool
@@ -536,7 +580,7 @@ class BillingAttachInvoiceModeTypedDict(TypedDict):
r"""If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review."""
class BillingAttachInvoiceMode(BaseModel):
class AttachInvoiceMode(BaseModel):
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. This uses Stripe's send_invoice collection method."""
enabled: bool
@@ -565,14 +609,14 @@ class BillingAttachInvoiceMode(BaseModel):
return m
BillingAttachProrationBehavior = Literal[
AttachProrationBehavior = Literal[
"prorate_immediately",
"none",
]
r"""How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges."""
class BillingAttachAttachDiscountTypedDict(TypedDict):
class AttachAttachDiscountTypedDict(TypedDict):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: NotRequired[str]
@@ -581,7 +625,7 @@ class BillingAttachAttachDiscountTypedDict(TypedDict):
r"""The promotion code to apply as a discount."""
class BillingAttachAttachDiscount(BaseModel):
class AttachAttachDiscount(BaseModel):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: Optional[str] = None
@@ -607,7 +651,7 @@ class BillingAttachAttachDiscount(BaseModel):
return m
BillingAttachPlanSchedule = Literal[
AttachPlanSchedule = Literal[
"immediate",
"end_of_cycle",
]
@@ -621,24 +665,26 @@ class AttachParamsTypedDict(TypedDict):
r"""The ID of the plan."""
entity_id: NotRequired[str]
r"""The ID of the entity to attach the plan to."""
feature_quantities: NotRequired[List[BillingAttachFeatureQuantityTypedDict]]
feature_quantities: NotRequired[List[AttachFeatureQuantityTypedDict]]
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan."""
version: NotRequired[float]
r"""The version of the plan to attach."""
customize: NotRequired[BillingAttachCustomizeTypedDict]
customize: NotRequired[AttachCustomizeTypedDict]
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
invoice_mode: NotRequired[BillingAttachInvoiceModeTypedDict]
invoice_mode: NotRequired[AttachInvoiceModeTypedDict]
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. This uses Stripe's send_invoice collection method."""
proration_behavior: NotRequired[BillingAttachProrationBehavior]
proration_behavior: NotRequired[AttachProrationBehavior]
r"""How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges."""
discounts: NotRequired[List[BillingAttachAttachDiscountTypedDict]]
discounts: NotRequired[List[AttachAttachDiscountTypedDict]]
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: NotRequired[str]
r"""URL to redirect to after successful checkout."""
new_billing_subscription: NotRequired[bool]
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
plan_schedule: NotRequired[BillingAttachPlanSchedule]
plan_schedule: NotRequired[AttachPlanSchedule]
r"""When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled."""
checkout_session_params: NotRequired[Dict[str, Any]]
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
class AttachParams(BaseModel):
@@ -651,22 +697,22 @@ class AttachParams(BaseModel):
entity_id: Optional[str] = None
r"""The ID of the entity to attach the plan to."""
feature_quantities: Optional[List[BillingAttachFeatureQuantity]] = None
feature_quantities: Optional[List[AttachFeatureQuantity]] = None
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan."""
version: Optional[float] = None
r"""The version of the plan to attach."""
customize: Optional[BillingAttachCustomize] = None
customize: Optional[AttachCustomize] = None
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
invoice_mode: Optional[BillingAttachInvoiceMode] = None
invoice_mode: Optional[AttachInvoiceMode] = None
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. This uses Stripe's send_invoice collection method."""
proration_behavior: Optional[BillingAttachProrationBehavior] = None
proration_behavior: Optional[AttachProrationBehavior] = None
r"""How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges."""
discounts: Optional[List[BillingAttachAttachDiscount]] = None
discounts: Optional[List[AttachAttachDiscount]] = None
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: Optional[str] = None
@@ -675,9 +721,12 @@ class AttachParams(BaseModel):
new_billing_subscription: Optional[bool] = None
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
plan_schedule: Optional[BillingAttachPlanSchedule] = None
plan_schedule: Optional[AttachPlanSchedule] = None
r"""When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled."""
checkout_session_params: Optional[Dict[str, Any]] = None
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
@@ -692,6 +741,7 @@ class AttachParams(BaseModel):
"success_url",
"new_billing_subscription",
"plan_schedule",
"checkout_session_params",
]
)
serialized = handler(self)
@@ -708,7 +758,7 @@ class AttachParams(BaseModel):
return m
class BillingAttachInvoiceTypedDict(TypedDict):
class AttachInvoiceTypedDict(TypedDict):
r"""Invoice details if an invoice was created. Only present when a charge was made."""
status: Nullable[str]
@@ -723,7 +773,7 @@ class BillingAttachInvoiceTypedDict(TypedDict):
r"""URL to the hosted invoice page where the customer can view and pay the invoice."""
class BillingAttachInvoice(BaseModel):
class AttachInvoice(BaseModel):
r"""Invoice details if an invoice was created. Only present when a charge was made."""
status: Nullable[str]
@@ -756,7 +806,7 @@ class BillingAttachInvoice(BaseModel):
return m
BillingAttachCode = Union[
AttachCode = Union[
Literal[
"3ds_required",
"payment_method_required",
@@ -767,26 +817,26 @@ BillingAttachCode = Union[
r"""The type of action required to complete the payment."""
class BillingAttachRequiredActionTypedDict(TypedDict):
class AttachRequiredActionTypedDict(TypedDict):
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
code: BillingAttachCode
code: AttachCode
r"""The type of action required to complete the payment."""
reason: str
r"""A human-readable explanation of why this action is required."""
class BillingAttachRequiredAction(BaseModel):
class AttachRequiredAction(BaseModel):
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
code: BillingAttachCode
code: AttachCode
r"""The type of action required to complete the payment."""
reason: str
r"""A human-readable explanation of why this action is required."""
class BillingAttachResponseTypedDict(TypedDict):
class AttachResponseTypedDict(TypedDict):
r"""OK"""
customer_id: str
@@ -795,13 +845,13 @@ class BillingAttachResponseTypedDict(TypedDict):
r"""URL to redirect the customer to complete payment. Null if no payment action is required."""
entity_id: NotRequired[str]
r"""The ID of the entity, if the plan was attached to an entity."""
invoice: NotRequired[BillingAttachInvoiceTypedDict]
invoice: NotRequired[AttachInvoiceTypedDict]
r"""Invoice details if an invoice was created. Only present when a charge was made."""
required_action: NotRequired[BillingAttachRequiredActionTypedDict]
required_action: NotRequired[AttachRequiredActionTypedDict]
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
class BillingAttachResponse(BaseModel):
class AttachResponse(BaseModel):
r"""OK"""
customer_id: str
@@ -813,10 +863,10 @@ class BillingAttachResponse(BaseModel):
entity_id: Optional[str] = None
r"""The ID of the entity, if the plan was attached to an entity."""
invoice: Optional[BillingAttachInvoice] = None
invoice: Optional[AttachInvoice] = None
r"""Invoice details if an invoice was created. Only present when a charge was made."""
required_action: Optional[BillingAttachRequiredAction] = None
required_action: Optional[AttachRequiredAction] = None
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
@model_serializer(mode="wrap")

View File

@@ -227,6 +227,7 @@ BalanceTo = TypeAliasType("BalanceTo", Union[float, str])
class BalanceTierTypedDict(TypedDict):
to: BalanceToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class BalanceTier(BaseModel):
@@ -234,6 +235,43 @@ class BalanceTier(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
BalanceTierBehavior = Union[
Literal[
"graduated",
"volume",
],
UnrecognizedStr,
]
r"""How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier)."""
BalanceBillingMethod = Union[
Literal[
@@ -256,6 +294,8 @@ class BalancePriceTypedDict(TypedDict):
r"""The per-unit price amount."""
tiers: NotRequired[List[BalanceTierTypedDict]]
r"""Tiered pricing configuration if applicable."""
tier_behavior: NotRequired[BalanceTierBehavior]
r"""How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier)."""
class BalancePrice(BaseModel):
@@ -274,9 +314,12 @@ class BalancePrice(BaseModel):
tiers: Optional[List[BalanceTier]] = None
r"""Tiered pricing configuration if applicable."""
tier_behavior: Optional[BalanceTierBehavior] = None
r"""How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier)."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["amount", "tiers"])
optional_fields = set(["amount", "tiers", "tier_behavior"])
nullable_fields = set(["max_purchase"])
serialized = handler(self)
m = {}

View File

@@ -193,6 +193,7 @@ BillingUpdateTo = TypeAliasType("BillingUpdateTo", Union[float, str])
class BillingUpdateTierTypedDict(TypedDict):
to: BillingUpdateToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class BillingUpdateTier(BaseModel):
@@ -200,6 +201,39 @@ class BillingUpdateTier(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
BillingUpdateTierBehavior = Literal[
"graduated",
"volume",
]
BillingUpdateItemPriceInterval = Literal[
"one_off",
@@ -229,7 +263,8 @@ class BillingUpdatePriceTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[BillingUpdateTierTypedDict]]
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[BillingUpdateTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
@@ -251,7 +286,9 @@ class BillingUpdatePrice(BaseModel):
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[BillingUpdateTier]] = None
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[BillingUpdateTierBehavior] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -265,7 +302,14 @@ class BillingUpdatePrice(BaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["amount", "tiers", "interval_count", "billing_units", "max_purchase"]
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}

View File

@@ -109,7 +109,7 @@ class CheckParams(BaseModel):
return m
Scenario = Union[
CheckScenario = Union[
Literal[
"usage_limit",
"feature_flag",
@@ -184,6 +184,8 @@ class TiersTypedDict(TypedDict):
r"""The maximum amount of usage for this tier."""
amount: float
r"""The price of the product item for this tier."""
flat_amount: NotRequired[Nullable[float]]
r"""A flat fee charged for this tier, in addition to the per-unit amount."""
class Tiers(BaseModel):
@@ -193,6 +195,43 @@ class Tiers(BaseModel):
amount: float
r"""The price of the product item for this tier."""
flat_amount: OptionalNullable[float] = UNSET
r"""A flat fee charged for this tier, in addition to the per-unit amount."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
CheckTierBehavior = Union[
Literal[
"graduated",
"volume",
],
UnrecognizedStr,
]
UsageModel = Union[
Literal[
@@ -368,6 +407,8 @@ class CheckItemTypedDict(TypedDict):
r"""The price of the product item. Should be `null` if tiered pricing is set."""
tiers: NotRequired[Nullable[List[TiersTypedDict]]]
r"""Tiered pricing for the product item. Not applicable for fixed price items."""
tier_behavior: NotRequired[Nullable[CheckTierBehavior]]
r"""How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier). Defaults to graduated."""
usage_model: NotRequired[Nullable[UsageModel]]
r"""Whether the feature should be prepaid upfront or billed for how much they use end of billing period."""
billing_units: NotRequired[Nullable[float]]
@@ -413,6 +454,9 @@ class CheckItem(BaseModel):
tiers: OptionalNullable[List[Tiers]] = UNSET
r"""Tiered pricing for the product item. Not applicable for fixed price items."""
tier_behavior: OptionalNullable[CheckTierBehavior] = UNSET
r"""How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier). Defaults to graduated."""
usage_model: OptionalNullable[UsageModel] = UNSET
r"""Whether the feature should be prepaid upfront or billed for how much they use end of billing period."""
@@ -449,6 +493,7 @@ class CheckItem(BaseModel):
"interval_count",
"price",
"tiers",
"tier_behavior",
"usage_model",
"billing_units",
"reset_usage_when_enabled",
@@ -469,6 +514,7 @@ class CheckItem(BaseModel):
"interval_count",
"price",
"tiers",
"tier_behavior",
"usage_model",
"billing_units",
"reset_usage_when_enabled",
@@ -740,7 +786,7 @@ class Product(BaseModel):
class PreviewTypedDict(TypedDict):
r"""Upgrade/upsell information when access is denied. Only present if with_preview was true and allowed is false."""
scenario: Scenario
scenario: CheckScenario
r"""The reason access was denied. 'usage_limit' means the customer exceeded their balance, 'feature_flag' means the feature is not included in their plan."""
title: str
r"""A title suitable for displaying in a paywall or upgrade modal."""
@@ -757,7 +803,7 @@ class PreviewTypedDict(TypedDict):
class Preview(BaseModel):
r"""Upgrade/upsell information when access is denied. Only present if with_preview was true and allowed is false."""
scenario: Scenario
scenario: CheckScenario
r"""The reason access was denied. 'usage_limit' means the customer exceeded their balance, 'feature_flag' means the feature is not included in their plan."""
title: str

View File

@@ -155,6 +155,7 @@ CreatePlanToRequest = TypeAliasType("CreatePlanToRequest", Union[float, str])
class CreatePlanTierRequestTypedDict(TypedDict):
to: CreatePlanToRequestTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class CreatePlanTierRequest(BaseModel):
@@ -162,6 +163,39 @@ class CreatePlanTierRequest(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
CreatePlanTierBehaviorRequest = Literal[
"graduated",
"volume",
]
CreatePlanItemPriceIntervalRequest = Literal[
"one_off",
@@ -191,7 +225,8 @@ class CreatePlanItemPriceRequestTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[CreatePlanTierRequestTypedDict]]
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[CreatePlanTierBehaviorRequest]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
@@ -213,7 +248,9 @@ class CreatePlanItemPriceRequest(BaseModel):
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[CreatePlanTierRequest]] = None
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[CreatePlanTierBehaviorRequest] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -227,7 +264,14 @@ class CreatePlanItemPriceRequest(BaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["amount", "tiers", "interval_count", "billing_units", "max_purchase"]
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}
@@ -779,6 +823,7 @@ CreatePlanToResponse = TypeAliasType("CreatePlanToResponse", Union[float, str])
class CreatePlanTierResponseTypedDict(TypedDict):
to: CreatePlanToResponseTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class CreatePlanTierResponse(BaseModel):
@@ -786,6 +831,42 @@ class CreatePlanTierResponse(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
CreatePlanTierBehaviorResponse = Union[
Literal[
"graduated",
"volume",
],
UnrecognizedStr,
]
CreatePlanPriceItemIntervalResponse = Union[
Literal[
@@ -823,7 +904,8 @@ class CreatePlanItemPriceResponseTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: NotRequired[List[CreatePlanTierResponseTypedDict]]
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: NotRequired[CreatePlanTierBehaviorResponse]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -845,14 +927,16 @@ class CreatePlanItemPriceResponse(BaseModel):
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: Optional[List[CreatePlanTierResponse]] = None
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: Optional[CreatePlanTierBehaviorResponse] = None
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["amount", "tiers", "interval_count"])
optional_fields = set(["amount", "tiers", "tier_behavior", "interval_count"])
nullable_fields = set(["max_purchase"])
serialized = handler(self)
m = {}
@@ -1085,6 +1169,54 @@ CreatePlanEnv = Union[
r"""Environment this plan belongs to ('sandbox' or 'live')."""
CreatePlanScenario = Union[
Literal[
"scheduled",
"active",
"new",
"renew",
"upgrade",
"downgrade",
"cancel",
"expired",
"past_due",
],
UnrecognizedStr,
]
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
class CreatePlanCustomerEligibilityTypedDict(TypedDict):
scenario: CreatePlanScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: NotRequired[bool]
r"""Whether a free trial is available for this customer."""
class CreatePlanCustomerEligibility(BaseModel):
scenario: CreatePlanScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: Optional[bool] = None
r"""Whether a free trial is available for this customer."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["trial_available"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class CreatePlanResponseTypedDict(TypedDict):
r"""A plan defines a set of features, pricing, and entitlements that can be attached to customers."""
@@ -1116,6 +1248,7 @@ class CreatePlanResponseTypedDict(TypedDict):
r"""If this is a variant, the ID of the base plan it was created from."""
free_trial: NotRequired[CreatePlanFreeTrialResponseTypedDict]
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: NotRequired[CreatePlanCustomerEligibilityTypedDict]
class CreatePlanResponse(BaseModel):
@@ -1163,9 +1296,11 @@ class CreatePlanResponse(BaseModel):
free_trial: Optional[CreatePlanFreeTrialResponse] = None
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: Optional[CreatePlanCustomerEligibility] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["free_trial"])
optional_fields = set(["free_trial", "customer_eligibility"])
nullable_fields = set(["description", "group", "price", "base_variant_id"])
serialized = handler(self)
m = {}

View File

@@ -329,6 +329,7 @@ GetPlanTo = TypeAliasType("GetPlanTo", Union[float, str])
class GetPlanTierTypedDict(TypedDict):
to: GetPlanToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class GetPlanTier(BaseModel):
@@ -336,6 +337,42 @@ class GetPlanTier(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
GetPlanTierBehavior = Union[
Literal[
"graduated",
"volume",
],
UnrecognizedStr,
]
GetPlanPriceItemInterval = Union[
Literal[
@@ -373,7 +410,8 @@ class GetPlanItemPriceTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: NotRequired[List[GetPlanTierTypedDict]]
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: NotRequired[GetPlanTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -395,14 +433,16 @@ class GetPlanItemPrice(BaseModel):
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: Optional[List[GetPlanTier]] = None
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: Optional[GetPlanTierBehavior] = None
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["amount", "tiers", "interval_count"])
optional_fields = set(["amount", "tiers", "tier_behavior", "interval_count"])
nullable_fields = set(["max_purchase"])
serialized = handler(self)
m = {}
@@ -635,6 +675,54 @@ GetPlanEnv = Union[
r"""Environment this plan belongs to ('sandbox' or 'live')."""
GetPlanScenario = Union[
Literal[
"scheduled",
"active",
"new",
"renew",
"upgrade",
"downgrade",
"cancel",
"expired",
"past_due",
],
UnrecognizedStr,
]
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
class GetPlanCustomerEligibilityTypedDict(TypedDict):
scenario: GetPlanScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: NotRequired[bool]
r"""Whether a free trial is available for this customer."""
class GetPlanCustomerEligibility(BaseModel):
scenario: GetPlanScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: Optional[bool] = None
r"""Whether a free trial is available for this customer."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["trial_available"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class GetPlanResponseTypedDict(TypedDict):
r"""A plan defines a set of features, pricing, and entitlements that can be attached to customers."""
@@ -666,6 +754,7 @@ class GetPlanResponseTypedDict(TypedDict):
r"""If this is a variant, the ID of the base plan it was created from."""
free_trial: NotRequired[GetPlanFreeTrialTypedDict]
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: NotRequired[GetPlanCustomerEligibilityTypedDict]
class GetPlanResponse(BaseModel):
@@ -713,9 +802,11 @@ class GetPlanResponse(BaseModel):
free_trial: Optional[GetPlanFreeTrial] = None
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: Optional[GetPlanCustomerEligibility] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["free_trial"])
optional_fields = set(["free_trial", "customer_eligibility"])
nullable_fields = set(["description", "group", "price", "base_variant_id"])
serialized = handler(self)
m = {}

View File

@@ -334,6 +334,7 @@ ListPlansTo = TypeAliasType("ListPlansTo", Union[float, str])
class ListPlansTierTypedDict(TypedDict):
to: ListPlansToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class ListPlansTier(BaseModel):
@@ -341,6 +342,42 @@ class ListPlansTier(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
ListPlansTierBehavior = Union[
Literal[
"graduated",
"volume",
],
UnrecognizedStr,
]
ListPlansPriceItemInterval = Union[
Literal[
@@ -378,7 +415,8 @@ class ListPlansItemPriceTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: NotRequired[List[ListPlansTierTypedDict]]
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: NotRequired[ListPlansTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -400,14 +438,16 @@ class ListPlansItemPrice(BaseModel):
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: Optional[List[ListPlansTier]] = None
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: Optional[ListPlansTierBehavior] = None
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["amount", "tiers", "interval_count"])
optional_fields = set(["amount", "tiers", "tier_behavior", "interval_count"])
nullable_fields = set(["max_purchase"])
serialized = handler(self)
m = {}
@@ -640,6 +680,54 @@ ListPlansEnv = Union[
r"""Environment this plan belongs to ('sandbox' or 'live')."""
ListPlansScenario = Union[
Literal[
"scheduled",
"active",
"new",
"renew",
"upgrade",
"downgrade",
"cancel",
"expired",
"past_due",
],
UnrecognizedStr,
]
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
class ListPlansCustomerEligibilityTypedDict(TypedDict):
scenario: ListPlansScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: NotRequired[bool]
r"""Whether a free trial is available for this customer."""
class ListPlansCustomerEligibility(BaseModel):
scenario: ListPlansScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: Optional[bool] = None
r"""Whether a free trial is available for this customer."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["trial_available"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class ListPlansListTypedDict(TypedDict):
r"""A plan defines a set of features, pricing, and entitlements that can be attached to customers."""
@@ -671,6 +759,7 @@ class ListPlansListTypedDict(TypedDict):
r"""If this is a variant, the ID of the base plan it was created from."""
free_trial: NotRequired[ListPlansFreeTrialTypedDict]
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: NotRequired[ListPlansCustomerEligibilityTypedDict]
class ListPlansList(BaseModel):
@@ -718,9 +807,11 @@ class ListPlansList(BaseModel):
free_trial: Optional[ListPlansFreeTrial] = None
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: Optional[ListPlansCustomerEligibility] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["free_trial"])
optional_fields = set(["free_trial", "customer_eligibility"])
nullable_fields = set(["description", "group", "price", "base_variant_id"])
serialized = handler(self)
m = {}

View File

@@ -0,0 +1,958 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
from .customerdata import CustomerData, CustomerDataTypedDict
from autumn_sdk.types import (
BaseModel,
Nullable,
OptionalNullable,
UNSET,
UNSET_SENTINEL,
UnrecognizedStr,
)
from autumn_sdk.utils import FieldMetadata, HeaderMetadata
import pydantic
from pydantic import model_serializer
from typing import Any, Dict, List, Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
class MultiAttachGlobalsTypedDict(TypedDict):
x_api_version: NotRequired[str]
class MultiAttachGlobals(BaseModel):
x_api_version: Annotated[
Optional[str],
pydantic.Field(alias="x-api-version"),
FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
] = "2.1"
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["x-api-version"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
MultiAttachPriceInterval = Literal[
"one_off",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Billing interval (e.g. 'month', 'year')."""
class MultiAttachBasePriceTypedDict(TypedDict):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: MultiAttachPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
class MultiAttachBasePrice(BaseModel):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: MultiAttachPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["interval_count"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
MultiAttachResetInterval = Literal[
"one_off",
"minute",
"hour",
"day",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
class MultiAttachResetTypedDict(TypedDict):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: MultiAttachResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: NotRequired[float]
r"""Number of intervals between resets. Defaults to 1."""
class MultiAttachReset(BaseModel):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: MultiAttachResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: Optional[float] = None
r"""Number of intervals between resets. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["interval_count"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
MultiAttachToTypedDict = TypeAliasType("MultiAttachToTypedDict", Union[float, str])
MultiAttachTo = TypeAliasType("MultiAttachTo", Union[float, str])
class MultiAttachTierTypedDict(TypedDict):
to: MultiAttachToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class MultiAttachTier(BaseModel):
to: MultiAttachTo
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
MultiAttachTierBehavior = Literal[
"graduated",
"volume",
]
MultiAttachItemPriceInterval = Literal[
"one_off",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Billing interval. For consumable features, should match reset.interval."""
MultiAttachBillingMethod = Literal[
"prepaid",
"usage_based",
]
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
class MultiAttachPriceTypedDict(TypedDict):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: MultiAttachItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: MultiAttachBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[MultiAttachTierTypedDict]]
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[MultiAttachTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
max_purchase: NotRequired[float]
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
class MultiAttachPrice(BaseModel):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: MultiAttachItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: MultiAttachBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: Optional[float] = None
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[MultiAttachTier]] = None
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[MultiAttachTierBehavior] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: Optional[float] = 1
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
max_purchase: Optional[float] = None
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
MultiAttachOnIncrease = Literal[
"bill_immediately",
"prorate_immediately",
"prorate_next_cycle",
"bill_next_cycle",
]
r"""Billing behavior when quantity increases mid-cycle."""
MultiAttachOnDecrease = Literal[
"prorate",
"prorate_immediately",
"prorate_next_cycle",
"none",
"no_prorations",
]
r"""Credit behavior when quantity decreases mid-cycle."""
class MultiAttachProrationTypedDict(TypedDict):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: MultiAttachOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: MultiAttachOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
class MultiAttachProration(BaseModel):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: MultiAttachOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: MultiAttachOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
MultiAttachExpiryDurationType = Literal[
"month",
"forever",
]
r"""When rolled over units expire."""
class MultiAttachRolloverTypedDict(TypedDict):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: MultiAttachExpiryDurationType
r"""When rolled over units expire."""
max: NotRequired[float]
r"""Max rollover units. Omit for unlimited rollover."""
expiry_duration_length: NotRequired[float]
r"""Number of periods before expiry."""
class MultiAttachRollover(BaseModel):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: MultiAttachExpiryDurationType
r"""When rolled over units expire."""
max: Optional[float] = None
r"""Max rollover units. Omit for unlimited rollover."""
expiry_duration_length: Optional[float] = None
r"""Number of periods before expiry."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["max", "expiry_duration_length"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class MultiAttachPlanItemTypedDict(TypedDict):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
r"""The ID of the feature to configure."""
included: NotRequired[float]
r"""Number of free units included. Balance resets to this each interval for consumable features."""
unlimited: NotRequired[bool]
r"""If true, customer has unlimited access to this feature."""
reset: NotRequired[MultiAttachResetTypedDict]
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: NotRequired[MultiAttachPriceTypedDict]
r"""Pricing for usage beyond included units. Omit for free features."""
proration: NotRequired[MultiAttachProrationTypedDict]
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: NotRequired[MultiAttachRolloverTypedDict]
r"""Rollover config for unused units. If set, unused included units carry over."""
class MultiAttachPlanItem(BaseModel):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
r"""The ID of the feature to configure."""
included: Optional[float] = None
r"""Number of free units included. Balance resets to this each interval for consumable features."""
unlimited: Optional[bool] = None
r"""If true, customer has unlimited access to this feature."""
reset: Optional[MultiAttachReset] = None
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: Optional[MultiAttachPrice] = None
r"""Pricing for usage beyond included units. Omit for free features."""
proration: Optional[MultiAttachProration] = None
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: Optional[MultiAttachRollover] = None
r"""Rollover config for unused units. If set, unused included units carry over."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["included", "unlimited", "reset", "price", "proration", "rollover"]
)
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class MultiAttachCustomizeTypedDict(TypedDict):
r"""Customize the plan to attach. Can override the price or items."""
price: NotRequired[Nullable[MultiAttachBasePriceTypedDict]]
r"""Override the base price of the plan. Pass null to remove the base price."""
items: NotRequired[List[MultiAttachPlanItemTypedDict]]
r"""Override the items in the plan."""
class MultiAttachCustomize(BaseModel):
r"""Customize the plan to attach. Can override the price or items."""
price: OptionalNullable[MultiAttachBasePrice] = UNSET
r"""Override the base price of the plan. Pass null to remove the base price."""
items: Optional[List[MultiAttachPlanItem]] = None
r"""Override the items in the plan."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["price", "items"])
nullable_fields = set(["price"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
class MultiAttachFeatureQuantityTypedDict(TypedDict):
r"""Quantity configuration for a prepaid feature."""
feature_id: str
r"""The ID of the feature to set quantity for."""
quantity: NotRequired[float]
r"""The quantity of the feature."""
adjustable: NotRequired[bool]
r"""Whether the customer can adjust the quantity."""
class MultiAttachFeatureQuantity(BaseModel):
r"""Quantity configuration for a prepaid feature."""
feature_id: str
r"""The ID of the feature to set quantity for."""
quantity: Optional[float] = None
r"""The quantity of the feature."""
adjustable: Optional[bool] = None
r"""Whether the customer can adjust the quantity."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["quantity", "adjustable"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class MultiAttachPlanTypedDict(TypedDict):
plan_id: str
r"""The ID of the plan to attach."""
customize: NotRequired[MultiAttachCustomizeTypedDict]
r"""Customize the plan to attach. Can override the price or items."""
feature_quantities: NotRequired[List[MultiAttachFeatureQuantityTypedDict]]
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature."""
version: NotRequired[float]
r"""The version of the plan to attach."""
class MultiAttachPlan(BaseModel):
plan_id: str
r"""The ID of the plan to attach."""
customize: Optional[MultiAttachCustomize] = None
r"""Customize the plan to attach. Can override the price or items."""
feature_quantities: Optional[List[MultiAttachFeatureQuantity]] = None
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature."""
version: Optional[float] = None
r"""The version of the plan to attach."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["customize", "feature_quantities", "version"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
MultiAttachDurationType = Literal[
"day",
"month",
"year",
]
r"""Unit of time for the trial ('day', 'month', 'year')."""
class MultiAttachFreeTrialParamsTypedDict(TypedDict):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: NotRequired[MultiAttachDurationType]
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: NotRequired[bool]
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
class MultiAttachFreeTrialParams(BaseModel):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: Optional[MultiAttachDurationType] = "month"
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: Optional[bool] = True
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["duration_type", "card_required"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class MultiAttachInvoiceModeTypedDict(TypedDict):
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
enabled: bool
r"""When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method."""
enable_plan_immediately: NotRequired[bool]
r"""If true, enables the plan immediately even though the invoice is not paid yet."""
finalize: NotRequired[bool]
r"""If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review."""
class MultiAttachInvoiceMode(BaseModel):
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
enabled: bool
r"""When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method."""
enable_plan_immediately: Optional[bool] = False
r"""If true, enables the plan immediately even though the invoice is not paid yet."""
finalize: Optional[bool] = True
r"""If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["enable_plan_immediately", "finalize"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class MultiAttachAttachDiscountTypedDict(TypedDict):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: NotRequired[str]
r"""The ID of the reward to apply as a discount."""
promotion_code: NotRequired[str]
r"""The promotion code to apply as a discount."""
class MultiAttachAttachDiscount(BaseModel):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: Optional[str] = None
r"""The ID of the reward to apply as a discount."""
promotion_code: Optional[str] = None
r"""The promotion code to apply as a discount."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["reward_id", "promotion_code"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
MultiAttachRedirectMode = Literal[
"always",
"if_required",
"never",
]
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
class MultiAttachEntityDataTypedDict(TypedDict):
feature_id: str
r"""The feature ID that this entity is associated with"""
name: NotRequired[str]
r"""Name of the entity"""
class MultiAttachEntityData(BaseModel):
feature_id: str
r"""The feature ID that this entity is associated with"""
name: Optional[str] = None
r"""Name of the entity"""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["name"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class MultiAttachParamsTypedDict(TypedDict):
customer_id: str
r"""The ID of the customer to attach the plans to."""
plans: List[MultiAttachPlanTypedDict]
r"""The list of plans to attach to the customer."""
entity_id: NotRequired[str]
r"""The ID of the entity to attach the plans to."""
free_trial: NotRequired[Nullable[MultiAttachFreeTrialParamsTypedDict]]
r"""Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial."""
invoice_mode: NotRequired[MultiAttachInvoiceModeTypedDict]
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
discounts: NotRequired[List[MultiAttachAttachDiscountTypedDict]]
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: NotRequired[str]
r"""URL to redirect to after successful checkout."""
checkout_session_params: NotRequired[Dict[str, Any]]
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
redirect_mode: NotRequired[MultiAttachRedirectMode]
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
new_billing_subscription: NotRequired[bool]
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
customer_data: NotRequired[CustomerDataTypedDict]
r"""Customer details to set when creating a customer"""
entity_data: NotRequired[MultiAttachEntityDataTypedDict]
class MultiAttachParams(BaseModel):
customer_id: str
r"""The ID of the customer to attach the plans to."""
plans: List[MultiAttachPlan]
r"""The list of plans to attach to the customer."""
entity_id: Optional[str] = None
r"""The ID of the entity to attach the plans to."""
free_trial: OptionalNullable[MultiAttachFreeTrialParams] = UNSET
r"""Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial."""
invoice_mode: Optional[MultiAttachInvoiceMode] = None
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
discounts: Optional[List[MultiAttachAttachDiscount]] = None
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: Optional[str] = None
r"""URL to redirect to after successful checkout."""
checkout_session_params: Optional[Dict[str, Any]] = None
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
redirect_mode: Optional[MultiAttachRedirectMode] = "if_required"
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
new_billing_subscription: Optional[bool] = None
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
customer_data: Optional[CustomerData] = None
r"""Customer details to set when creating a customer"""
entity_data: Optional[MultiAttachEntityData] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
[
"entity_id",
"free_trial",
"invoice_mode",
"discounts",
"success_url",
"checkout_session_params",
"redirect_mode",
"new_billing_subscription",
"customer_data",
"entity_data",
]
)
nullable_fields = set(["free_trial"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
class MultiAttachInvoiceTypedDict(TypedDict):
r"""Invoice details if an invoice was created. Only present when a charge was made."""
status: Nullable[str]
r"""The status of the invoice (e.g., 'paid', 'open', 'draft')."""
stripe_id: str
r"""The Stripe invoice ID."""
total: float
r"""The total amount of the invoice in cents."""
currency: str
r"""The three-letter ISO currency code (e.g., 'usd')."""
hosted_invoice_url: Nullable[str]
r"""URL to the hosted invoice page where the customer can view and pay the invoice."""
class MultiAttachInvoice(BaseModel):
r"""Invoice details if an invoice was created. Only present when a charge was made."""
status: Nullable[str]
r"""The status of the invoice (e.g., 'paid', 'open', 'draft')."""
stripe_id: str
r"""The Stripe invoice ID."""
total: float
r"""The total amount of the invoice in cents."""
currency: str
r"""The three-letter ISO currency code (e.g., 'usd')."""
hosted_invoice_url: Nullable[str]
r"""URL to the hosted invoice page where the customer can view and pay the invoice."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
m[k] = val
return m
MultiAttachCode = Union[
Literal[
"3ds_required",
"payment_method_required",
"payment_failed",
],
UnrecognizedStr,
]
r"""The type of action required to complete the payment."""
class MultiAttachRequiredActionTypedDict(TypedDict):
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
code: MultiAttachCode
r"""The type of action required to complete the payment."""
reason: str
r"""A human-readable explanation of why this action is required."""
class MultiAttachRequiredAction(BaseModel):
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
code: MultiAttachCode
r"""The type of action required to complete the payment."""
reason: str
r"""A human-readable explanation of why this action is required."""
class MultiAttachResponseTypedDict(TypedDict):
r"""OK"""
customer_id: str
r"""The ID of the customer."""
payment_url: Nullable[str]
r"""URL to redirect the customer to complete payment. Null if no payment action is required."""
entity_id: NotRequired[str]
r"""The ID of the entity, if the plan was attached to an entity."""
invoice: NotRequired[MultiAttachInvoiceTypedDict]
r"""Invoice details if an invoice was created. Only present when a charge was made."""
required_action: NotRequired[MultiAttachRequiredActionTypedDict]
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
class MultiAttachResponse(BaseModel):
r"""OK"""
customer_id: str
r"""The ID of the customer."""
payment_url: Nullable[str]
r"""URL to redirect the customer to complete payment. Null if no payment action is required."""
entity_id: Optional[str] = None
r"""The ID of the entity, if the plan was attached to an entity."""
invoice: Optional[MultiAttachInvoice] = None
r"""Invoice details if an invoice was created. Only present when a charge was made."""
required_action: Optional[MultiAttachRequiredAction] = None
r"""Details about any action required to complete the payment. Present when the payment could not be processed automatically."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["entity_id", "invoice", "required_action"])
nullable_fields = set(["payment_url"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m

View File

@@ -268,6 +268,7 @@ PlanTo = TypeAliasType("PlanTo", Union[float, str])
class PlanTierTypedDict(TypedDict):
to: PlanToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class PlanTier(BaseModel):
@@ -275,6 +276,42 @@ class PlanTier(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
PlanTierBehavior = Union[
Literal[
"graduated",
"volume",
],
UnrecognizedStr,
]
PlanPriceItemInterval = Union[
Literal[
@@ -312,7 +349,8 @@ class PlanItemPriceTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: NotRequired[List[PlanTierTypedDict]]
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: NotRequired[PlanTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -334,14 +372,16 @@ class PlanItemPrice(BaseModel):
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: Optional[List[PlanTier]] = None
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: Optional[PlanTierBehavior] = None
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["amount", "tiers", "interval_count"])
optional_fields = set(["amount", "tiers", "tier_behavior", "interval_count"])
nullable_fields = set(["max_purchase"])
serialized = handler(self)
m = {}
@@ -574,6 +614,54 @@ PlanEnv = Union[
r"""Environment this plan belongs to ('sandbox' or 'live')."""
Scenario = Union[
Literal[
"scheduled",
"active",
"new",
"renew",
"upgrade",
"downgrade",
"cancel",
"expired",
"past_due",
],
UnrecognizedStr,
]
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
class CustomerEligibilityTypedDict(TypedDict):
scenario: Scenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: NotRequired[bool]
r"""Whether a free trial is available for this customer."""
class CustomerEligibility(BaseModel):
scenario: Scenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: Optional[bool] = None
r"""Whether a free trial is available for this customer."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["trial_available"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PlanTypedDict(TypedDict):
id: str
r"""Unique identifier for the plan."""
@@ -603,6 +691,7 @@ class PlanTypedDict(TypedDict):
r"""If this is a variant, the ID of the base plan it was created from."""
free_trial: NotRequired[FreeTrialTypedDict]
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: NotRequired[CustomerEligibilityTypedDict]
class Plan(BaseModel):
@@ -648,9 +737,11 @@ class Plan(BaseModel):
free_trial: Optional[FreeTrial] = None
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: Optional[CustomerEligibility] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["free_trial"])
optional_fields = set(["free_trial", "customer_eligibility"])
nullable_fields = set(["description", "group", "price", "base_variant_id"])
serialized = handler(self)
m = {}

View File

@@ -11,7 +11,7 @@ from autumn_sdk.types import (
from autumn_sdk.utils import FieldMetadata, HeaderMetadata
import pydantic
from pydantic import model_serializer
from typing import List, Literal, Optional, Union
from typing import Any, Dict, List, Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
@@ -192,6 +192,7 @@ PreviewAttachTo = TypeAliasType("PreviewAttachTo", Union[float, str])
class PreviewAttachTierTypedDict(TypedDict):
to: PreviewAttachToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class PreviewAttachTier(BaseModel):
@@ -199,6 +200,39 @@ class PreviewAttachTier(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
PreviewAttachTierBehavior = Literal[
"graduated",
"volume",
]
PreviewAttachItemPriceInterval = Literal[
"one_off",
@@ -228,7 +262,8 @@ class PreviewAttachPriceTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[PreviewAttachTierTypedDict]]
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[PreviewAttachTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
@@ -250,7 +285,9 @@ class PreviewAttachPrice(BaseModel):
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[PreviewAttachTier]] = None
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[PreviewAttachTierBehavior] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -264,7 +301,14 @@ class PreviewAttachPrice(BaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["amount", "tiers", "interval_count", "billing_units", "max_purchase"]
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}
@@ -638,6 +682,8 @@ class PreviewAttachParamsTypedDict(TypedDict):
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
plan_schedule: NotRequired[PreviewAttachPlanSchedule]
r"""When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled."""
checkout_session_params: NotRequired[Dict[str, Any]]
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
class PreviewAttachParams(BaseModel):
@@ -677,6 +723,9 @@ class PreviewAttachParams(BaseModel):
plan_schedule: Optional[PreviewAttachPlanSchedule] = None
r"""When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled."""
checkout_session_params: Optional[Dict[str, Any]] = None
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
@@ -691,6 +740,7 @@ class PreviewAttachParams(BaseModel):
"success_url",
"new_billing_subscription",
"plan_schedule",
"checkout_session_params",
]
)
serialized = handler(self)

View File

@@ -0,0 +1,973 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
from .customerdata import CustomerData, CustomerDataTypedDict
from autumn_sdk.types import (
BaseModel,
Nullable,
OptionalNullable,
UNSET,
UNSET_SENTINEL,
)
from autumn_sdk.utils import FieldMetadata, HeaderMetadata
import pydantic
from pydantic import model_serializer
from typing import Any, Dict, List, Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
class PreviewMultiAttachGlobalsTypedDict(TypedDict):
x_api_version: NotRequired[str]
class PreviewMultiAttachGlobals(BaseModel):
x_api_version: Annotated[
Optional[str],
pydantic.Field(alias="x-api-version"),
FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
] = "2.1"
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["x-api-version"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
PreviewMultiAttachPriceInterval = Literal[
"one_off",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Billing interval (e.g. 'month', 'year')."""
class PreviewMultiAttachBasePriceTypedDict(TypedDict):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: PreviewMultiAttachPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
class PreviewMultiAttachBasePrice(BaseModel):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: PreviewMultiAttachPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["interval_count"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
PreviewMultiAttachResetInterval = Literal[
"one_off",
"minute",
"hour",
"day",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
class PreviewMultiAttachResetTypedDict(TypedDict):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: PreviewMultiAttachResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: NotRequired[float]
r"""Number of intervals between resets. Defaults to 1."""
class PreviewMultiAttachReset(BaseModel):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: PreviewMultiAttachResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: Optional[float] = None
r"""Number of intervals between resets. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["interval_count"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
PreviewMultiAttachToTypedDict = TypeAliasType(
"PreviewMultiAttachToTypedDict", Union[float, str]
)
PreviewMultiAttachTo = TypeAliasType("PreviewMultiAttachTo", Union[float, str])
class PreviewMultiAttachTierTypedDict(TypedDict):
to: PreviewMultiAttachToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class PreviewMultiAttachTier(BaseModel):
to: PreviewMultiAttachTo
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
PreviewMultiAttachTierBehavior = Literal[
"graduated",
"volume",
]
PreviewMultiAttachItemPriceInterval = Literal[
"one_off",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Billing interval. For consumable features, should match reset.interval."""
PreviewMultiAttachBillingMethod = Literal[
"prepaid",
"usage_based",
]
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
class PreviewMultiAttachPriceTypedDict(TypedDict):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: PreviewMultiAttachItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: PreviewMultiAttachBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[PreviewMultiAttachTierTypedDict]]
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[PreviewMultiAttachTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
max_purchase: NotRequired[float]
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
class PreviewMultiAttachPrice(BaseModel):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: PreviewMultiAttachItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: PreviewMultiAttachBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: Optional[float] = None
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[PreviewMultiAttachTier]] = None
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[PreviewMultiAttachTierBehavior] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: Optional[float] = 1
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
max_purchase: Optional[float] = None
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
PreviewMultiAttachOnIncrease = Literal[
"bill_immediately",
"prorate_immediately",
"prorate_next_cycle",
"bill_next_cycle",
]
r"""Billing behavior when quantity increases mid-cycle."""
PreviewMultiAttachOnDecrease = Literal[
"prorate",
"prorate_immediately",
"prorate_next_cycle",
"none",
"no_prorations",
]
r"""Credit behavior when quantity decreases mid-cycle."""
class PreviewMultiAttachProrationTypedDict(TypedDict):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: PreviewMultiAttachOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: PreviewMultiAttachOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
class PreviewMultiAttachProration(BaseModel):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: PreviewMultiAttachOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: PreviewMultiAttachOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
PreviewMultiAttachExpiryDurationType = Literal[
"month",
"forever",
]
r"""When rolled over units expire."""
class PreviewMultiAttachRolloverTypedDict(TypedDict):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: PreviewMultiAttachExpiryDurationType
r"""When rolled over units expire."""
max: NotRequired[float]
r"""Max rollover units. Omit for unlimited rollover."""
expiry_duration_length: NotRequired[float]
r"""Number of periods before expiry."""
class PreviewMultiAttachRollover(BaseModel):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: PreviewMultiAttachExpiryDurationType
r"""When rolled over units expire."""
max: Optional[float] = None
r"""Max rollover units. Omit for unlimited rollover."""
expiry_duration_length: Optional[float] = None
r"""Number of periods before expiry."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["max", "expiry_duration_length"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachPlanItemTypedDict(TypedDict):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
r"""The ID of the feature to configure."""
included: NotRequired[float]
r"""Number of free units included. Balance resets to this each interval for consumable features."""
unlimited: NotRequired[bool]
r"""If true, customer has unlimited access to this feature."""
reset: NotRequired[PreviewMultiAttachResetTypedDict]
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: NotRequired[PreviewMultiAttachPriceTypedDict]
r"""Pricing for usage beyond included units. Omit for free features."""
proration: NotRequired[PreviewMultiAttachProrationTypedDict]
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: NotRequired[PreviewMultiAttachRolloverTypedDict]
r"""Rollover config for unused units. If set, unused included units carry over."""
class PreviewMultiAttachPlanItem(BaseModel):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
r"""The ID of the feature to configure."""
included: Optional[float] = None
r"""Number of free units included. Balance resets to this each interval for consumable features."""
unlimited: Optional[bool] = None
r"""If true, customer has unlimited access to this feature."""
reset: Optional[PreviewMultiAttachReset] = None
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: Optional[PreviewMultiAttachPrice] = None
r"""Pricing for usage beyond included units. Omit for free features."""
proration: Optional[PreviewMultiAttachProration] = None
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: Optional[PreviewMultiAttachRollover] = None
r"""Rollover config for unused units. If set, unused included units carry over."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["included", "unlimited", "reset", "price", "proration", "rollover"]
)
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachCustomizeTypedDict(TypedDict):
r"""Customize the plan to attach. Can override the price or items."""
price: NotRequired[Nullable[PreviewMultiAttachBasePriceTypedDict]]
r"""Override the base price of the plan. Pass null to remove the base price."""
items: NotRequired[List[PreviewMultiAttachPlanItemTypedDict]]
r"""Override the items in the plan."""
class PreviewMultiAttachCustomize(BaseModel):
r"""Customize the plan to attach. Can override the price or items."""
price: OptionalNullable[PreviewMultiAttachBasePrice] = UNSET
r"""Override the base price of the plan. Pass null to remove the base price."""
items: Optional[List[PreviewMultiAttachPlanItem]] = None
r"""Override the items in the plan."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["price", "items"])
nullable_fields = set(["price"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
class PreviewMultiAttachFeatureQuantityTypedDict(TypedDict):
r"""Quantity configuration for a prepaid feature."""
feature_id: str
r"""The ID of the feature to set quantity for."""
quantity: NotRequired[float]
r"""The quantity of the feature."""
adjustable: NotRequired[bool]
r"""Whether the customer can adjust the quantity."""
class PreviewMultiAttachFeatureQuantity(BaseModel):
r"""Quantity configuration for a prepaid feature."""
feature_id: str
r"""The ID of the feature to set quantity for."""
quantity: Optional[float] = None
r"""The quantity of the feature."""
adjustable: Optional[bool] = None
r"""Whether the customer can adjust the quantity."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["quantity", "adjustable"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachPlanTypedDict(TypedDict):
plan_id: str
r"""The ID of the plan to attach."""
customize: NotRequired[PreviewMultiAttachCustomizeTypedDict]
r"""Customize the plan to attach. Can override the price or items."""
feature_quantities: NotRequired[List[PreviewMultiAttachFeatureQuantityTypedDict]]
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature."""
version: NotRequired[float]
r"""The version of the plan to attach."""
class PreviewMultiAttachPlan(BaseModel):
plan_id: str
r"""The ID of the plan to attach."""
customize: Optional[PreviewMultiAttachCustomize] = None
r"""Customize the plan to attach. Can override the price or items."""
feature_quantities: Optional[List[PreviewMultiAttachFeatureQuantity]] = None
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature."""
version: Optional[float] = None
r"""The version of the plan to attach."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["customize", "feature_quantities", "version"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
PreviewMultiAttachDurationType = Literal[
"day",
"month",
"year",
]
r"""Unit of time for the trial ('day', 'month', 'year')."""
class PreviewMultiAttachFreeTrialParamsTypedDict(TypedDict):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: NotRequired[PreviewMultiAttachDurationType]
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: NotRequired[bool]
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
class PreviewMultiAttachFreeTrialParams(BaseModel):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: Optional[PreviewMultiAttachDurationType] = "month"
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: Optional[bool] = True
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["duration_type", "card_required"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachInvoiceModeTypedDict(TypedDict):
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
enabled: bool
r"""When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method."""
enable_plan_immediately: NotRequired[bool]
r"""If true, enables the plan immediately even though the invoice is not paid yet."""
finalize: NotRequired[bool]
r"""If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review."""
class PreviewMultiAttachInvoiceMode(BaseModel):
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
enabled: bool
r"""When true, creates an invoice and sends it to the customer instead of charging their card immediately. Uses Stripe's send_invoice collection method."""
enable_plan_immediately: Optional[bool] = False
r"""If true, enables the plan immediately even though the invoice is not paid yet."""
finalize: Optional[bool] = True
r"""If true, finalizes the invoice so it can be sent to the customer. If false, keeps it as a draft for manual review."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["enable_plan_immediately", "finalize"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachAttachDiscountTypedDict(TypedDict):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: NotRequired[str]
r"""The ID of the reward to apply as a discount."""
promotion_code: NotRequired[str]
r"""The promotion code to apply as a discount."""
class PreviewMultiAttachAttachDiscount(BaseModel):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: Optional[str] = None
r"""The ID of the reward to apply as a discount."""
promotion_code: Optional[str] = None
r"""The promotion code to apply as a discount."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["reward_id", "promotion_code"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
PreviewMultiAttachRedirectMode = Literal[
"always",
"if_required",
"never",
]
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
class PreviewMultiAttachEntityDataTypedDict(TypedDict):
feature_id: str
r"""The feature ID that this entity is associated with"""
name: NotRequired[str]
r"""Name of the entity"""
class PreviewMultiAttachEntityData(BaseModel):
feature_id: str
r"""The feature ID that this entity is associated with"""
name: Optional[str] = None
r"""Name of the entity"""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["name"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachParamsTypedDict(TypedDict):
customer_id: str
r"""The ID of the customer to attach the plans to."""
plans: List[PreviewMultiAttachPlanTypedDict]
r"""The list of plans to attach to the customer."""
entity_id: NotRequired[str]
r"""The ID of the entity to attach the plans to."""
free_trial: NotRequired[Nullable[PreviewMultiAttachFreeTrialParamsTypedDict]]
r"""Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial."""
invoice_mode: NotRequired[PreviewMultiAttachInvoiceModeTypedDict]
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
discounts: NotRequired[List[PreviewMultiAttachAttachDiscountTypedDict]]
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: NotRequired[str]
r"""URL to redirect to after successful checkout."""
checkout_session_params: NotRequired[Dict[str, Any]]
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
redirect_mode: NotRequired[PreviewMultiAttachRedirectMode]
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
new_billing_subscription: NotRequired[bool]
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
customer_data: NotRequired[CustomerDataTypedDict]
r"""Customer details to set when creating a customer"""
entity_data: NotRequired[PreviewMultiAttachEntityDataTypedDict]
class PreviewMultiAttachParams(BaseModel):
customer_id: str
r"""The ID of the customer to attach the plans to."""
plans: List[PreviewMultiAttachPlan]
r"""The list of plans to attach to the customer."""
entity_id: Optional[str] = None
r"""The ID of the entity to attach the plans to."""
free_trial: OptionalNullable[PreviewMultiAttachFreeTrialParams] = UNSET
r"""Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial."""
invoice_mode: Optional[PreviewMultiAttachInvoiceMode] = None
r"""Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately."""
discounts: Optional[List[PreviewMultiAttachAttachDiscount]] = None
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: Optional[str] = None
r"""URL to redirect to after successful checkout."""
checkout_session_params: Optional[Dict[str, Any]] = None
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
redirect_mode: Optional[PreviewMultiAttachRedirectMode] = "if_required"
r"""Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects."""
new_billing_subscription: Optional[bool] = None
r"""Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one."""
customer_data: Optional[CustomerData] = None
r"""Customer details to set when creating a customer"""
entity_data: Optional[PreviewMultiAttachEntityData] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
[
"entity_id",
"free_trial",
"invoice_mode",
"discounts",
"success_url",
"checkout_session_params",
"redirect_mode",
"new_billing_subscription",
"customer_data",
"entity_data",
]
)
nullable_fields = set(["free_trial"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
class PreviewMultiAttachDiscountTypedDict(TypedDict):
amount_off: float
percent_off: NotRequired[float]
stripe_coupon_id: NotRequired[str]
coupon_name: NotRequired[str]
class PreviewMultiAttachDiscount(BaseModel):
amount_off: Annotated[float, pydantic.Field(alias="amountOff")]
percent_off: Annotated[Optional[float], pydantic.Field(alias="percentOff")] = None
stripe_coupon_id: Annotated[
Optional[str], pydantic.Field(alias="stripeCouponId")
] = None
coupon_name: Annotated[Optional[str], pydantic.Field(alias="couponName")] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["percentOff", "stripeCouponId", "couponName"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachLineItemTypedDict(TypedDict):
title: str
r"""The title of the line item."""
description: str
r"""A detailed description of the line item."""
amount: float
r"""The amount in cents for this line item."""
discounts: NotRequired[List[PreviewMultiAttachDiscountTypedDict]]
r"""List of discounts applied to this line item."""
class PreviewMultiAttachLineItem(BaseModel):
title: str
r"""The title of the line item."""
description: str
r"""A detailed description of the line item."""
amount: float
r"""The amount in cents for this line item."""
discounts: Optional[List[PreviewMultiAttachDiscount]] = None
r"""List of discounts applied to this line item."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["discounts"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class PreviewMultiAttachNextCycleTypedDict(TypedDict):
r"""Preview of the next billing cycle, if applicable. This shows what the customer will be charged in subsequent cycles."""
starts_at: float
r"""Unix timestamp (milliseconds) when the next billing cycle starts."""
total: float
r"""The total amount in cents for the next cycle."""
class PreviewMultiAttachNextCycle(BaseModel):
r"""Preview of the next billing cycle, if applicable. This shows what the customer will be charged in subsequent cycles."""
starts_at: float
r"""Unix timestamp (milliseconds) when the next billing cycle starts."""
total: float
r"""The total amount in cents for the next cycle."""
class PreviewMultiAttachResponseTypedDict(TypedDict):
r"""OK"""
customer_id: str
r"""The ID of the customer."""
line_items: List[PreviewMultiAttachLineItemTypedDict]
r"""List of line items for the current billing period."""
total: float
r"""The total amount in cents for the current billing period."""
currency: str
r"""The three-letter ISO currency code (e.g., 'usd')."""
next_cycle: NotRequired[PreviewMultiAttachNextCycleTypedDict]
r"""Preview of the next billing cycle, if applicable. This shows what the customer will be charged in subsequent cycles."""
class PreviewMultiAttachResponse(BaseModel):
r"""OK"""
customer_id: str
r"""The ID of the customer."""
line_items: List[PreviewMultiAttachLineItem]
r"""List of line items for the current billing period."""
total: float
r"""The total amount in cents for the current billing period."""
currency: str
r"""The three-letter ISO currency code (e.g., 'usd')."""
next_cycle: Optional[PreviewMultiAttachNextCycle] = None
r"""Preview of the next billing cycle, if applicable. This shows what the customer will be charged in subsequent cycles."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["next_cycle"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
try:
PreviewMultiAttachDiscount.model_rebuild()
except NameError:
pass

View File

@@ -192,6 +192,7 @@ PreviewUpdateTo = TypeAliasType("PreviewUpdateTo", Union[float, str])
class PreviewUpdateTierTypedDict(TypedDict):
to: PreviewUpdateToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class PreviewUpdateTier(BaseModel):
@@ -199,6 +200,39 @@ class PreviewUpdateTier(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
PreviewUpdateTierBehavior = Literal[
"graduated",
"volume",
]
PreviewUpdateItemPriceInterval = Literal[
"one_off",
@@ -228,7 +262,8 @@ class PreviewUpdatePriceTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[PreviewUpdateTierTypedDict]]
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[PreviewUpdateTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
@@ -250,7 +285,9 @@ class PreviewUpdatePrice(BaseModel):
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[PreviewUpdateTier]] = None
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[PreviewUpdateTierBehavior] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -264,7 +301,14 @@ class PreviewUpdatePrice(BaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["amount", "tiers", "interval_count", "billing_units", "max_purchase"]
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}

View File

@@ -1,13 +1,18 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
from .customerdata import CustomerData, CustomerDataTypedDict
from autumn_sdk.types import BaseModel, UNSET_SENTINEL
from autumn_sdk.types import (
BaseModel,
Nullable,
OptionalNullable,
UNSET,
UNSET_SENTINEL,
)
from autumn_sdk.utils import FieldMetadata, HeaderMetadata
import pydantic
from pydantic import model_serializer
from typing import Any, Dict, Optional
from typing_extensions import Annotated, NotRequired, TypedDict
from typing import Any, Dict, List, Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
class SetupPaymentGlobalsTypedDict(TypedDict):
@@ -38,34 +43,641 @@ class SetupPaymentGlobals(BaseModel):
return m
class SetupPaymentParamsTypedDict(TypedDict):
customer_id: str
r"""The ID of the customer"""
success_url: NotRequired[str]
r"""URL to redirect to after successful payment setup. Must start with either http:// or https://"""
customer_data: NotRequired[CustomerDataTypedDict]
r"""Customer details to set when creating a customer"""
checkout_session_params: NotRequired[Dict[str, Any]]
r"""Additional parameters for the checkout session"""
class SetupPaymentFeatureQuantityTypedDict(TypedDict):
r"""Quantity configuration for a prepaid feature."""
feature_id: str
r"""The ID of the feature to set quantity for."""
quantity: NotRequired[float]
r"""The quantity of the feature."""
adjustable: NotRequired[bool]
r"""Whether the customer can adjust the quantity."""
class SetupPaymentParams(BaseModel):
customer_id: str
r"""The ID of the customer"""
class SetupPaymentFeatureQuantity(BaseModel):
r"""Quantity configuration for a prepaid feature."""
success_url: Optional[str] = None
r"""URL to redirect to after successful payment setup. Must start with either http:// or https://"""
feature_id: str
r"""The ID of the feature to set quantity for."""
customer_data: Optional[CustomerData] = None
r"""Customer details to set when creating a customer"""
quantity: Optional[float] = None
r"""The quantity of the feature."""
checkout_session_params: Optional[Dict[str, Any]] = None
r"""Additional parameters for the checkout session"""
adjustable: Optional[bool] = None
r"""Whether the customer can adjust the quantity."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["quantity", "adjustable"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
SetupPaymentPriceInterval = Literal[
"one_off",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Billing interval (e.g. 'month', 'year')."""
class SetupPaymentBasePriceTypedDict(TypedDict):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: SetupPaymentPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
class SetupPaymentBasePrice(BaseModel):
r"""Base price configuration for a plan."""
amount: float
r"""Base price amount for the plan."""
interval: SetupPaymentPriceInterval
r"""Billing interval (e.g. 'month', 'year')."""
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["interval_count"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
SetupPaymentResetInterval = Literal[
"one_off",
"minute",
"hour",
"day",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
class SetupPaymentResetTypedDict(TypedDict):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: SetupPaymentResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: NotRequired[float]
r"""Number of intervals between resets. Defaults to 1."""
class SetupPaymentReset(BaseModel):
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
interval: SetupPaymentResetInterval
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
interval_count: Optional[float] = None
r"""Number of intervals between resets. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["interval_count"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
SetupPaymentToTypedDict = TypeAliasType("SetupPaymentToTypedDict", Union[float, str])
SetupPaymentTo = TypeAliasType("SetupPaymentTo", Union[float, str])
class SetupPaymentTierTypedDict(TypedDict):
to: SetupPaymentToTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class SetupPaymentTier(BaseModel):
to: SetupPaymentTo
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
SetupPaymentTierBehavior = Literal[
"graduated",
"volume",
]
SetupPaymentItemPriceInterval = Literal[
"one_off",
"week",
"month",
"quarter",
"semi_annual",
"year",
]
r"""Billing interval. For consumable features, should match reset.interval."""
SetupPaymentBillingMethod = Literal[
"prepaid",
"usage_based",
]
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
class SetupPaymentPriceTypedDict(TypedDict):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: SetupPaymentItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: SetupPaymentBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[SetupPaymentTierTypedDict]]
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[SetupPaymentTierBehavior]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
max_purchase: NotRequired[float]
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
class SetupPaymentPrice(BaseModel):
r"""Pricing for usage beyond included units. Omit for free features."""
interval: SetupPaymentItemPriceInterval
r"""Billing interval. For consumable features, should match reset.interval."""
billing_method: SetupPaymentBillingMethod
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
amount: Optional[float] = None
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[SetupPaymentTier]] = None
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[SetupPaymentTierBehavior] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: Optional[float] = 1
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
max_purchase: Optional[float] = None
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["success_url", "customer_data", "checkout_session_params"]
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
SetupPaymentOnIncrease = Literal[
"bill_immediately",
"prorate_immediately",
"prorate_next_cycle",
"bill_next_cycle",
]
r"""Billing behavior when quantity increases mid-cycle."""
SetupPaymentOnDecrease = Literal[
"prorate",
"prorate_immediately",
"prorate_next_cycle",
"none",
"no_prorations",
]
r"""Credit behavior when quantity decreases mid-cycle."""
class SetupPaymentProrationTypedDict(TypedDict):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: SetupPaymentOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: SetupPaymentOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
class SetupPaymentProration(BaseModel):
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
on_increase: SetupPaymentOnIncrease
r"""Billing behavior when quantity increases mid-cycle."""
on_decrease: SetupPaymentOnDecrease
r"""Credit behavior when quantity decreases mid-cycle."""
SetupPaymentExpiryDurationType = Literal[
"month",
"forever",
]
r"""When rolled over units expire."""
class SetupPaymentRolloverTypedDict(TypedDict):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: SetupPaymentExpiryDurationType
r"""When rolled over units expire."""
max: NotRequired[float]
r"""Max rollover units. Omit for unlimited rollover."""
expiry_duration_length: NotRequired[float]
r"""Number of periods before expiry."""
class SetupPaymentRollover(BaseModel):
r"""Rollover config for unused units. If set, unused included units carry over."""
expiry_duration_type: SetupPaymentExpiryDurationType
r"""When rolled over units expire."""
max: Optional[float] = None
r"""Max rollover units. Omit for unlimited rollover."""
expiry_duration_length: Optional[float] = None
r"""Number of periods before expiry."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["max", "expiry_duration_length"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class SetupPaymentPlanItemTypedDict(TypedDict):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
r"""The ID of the feature to configure."""
included: NotRequired[float]
r"""Number of free units included. Balance resets to this each interval for consumable features."""
unlimited: NotRequired[bool]
r"""If true, customer has unlimited access to this feature."""
reset: NotRequired[SetupPaymentResetTypedDict]
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: NotRequired[SetupPaymentPriceTypedDict]
r"""Pricing for usage beyond included units. Omit for free features."""
proration: NotRequired[SetupPaymentProrationTypedDict]
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: NotRequired[SetupPaymentRolloverTypedDict]
r"""Rollover config for unused units. If set, unused included units carry over."""
class SetupPaymentPlanItem(BaseModel):
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
feature_id: str
r"""The ID of the feature to configure."""
included: Optional[float] = None
r"""Number of free units included. Balance resets to this each interval for consumable features."""
unlimited: Optional[bool] = None
r"""If true, customer has unlimited access to this feature."""
reset: Optional[SetupPaymentReset] = None
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
price: Optional[SetupPaymentPrice] = None
r"""Pricing for usage beyond included units. Omit for free features."""
proration: Optional[SetupPaymentProration] = None
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
rollover: Optional[SetupPaymentRollover] = None
r"""Rollover config for unused units. If set, unused included units carry over."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["included", "unlimited", "reset", "price", "proration", "rollover"]
)
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
SetupPaymentDurationType = Literal[
"day",
"month",
"year",
]
r"""Unit of time for the trial ('day', 'month', 'year')."""
class SetupPaymentFreeTrialParamsTypedDict(TypedDict):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: NotRequired[SetupPaymentDurationType]
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: NotRequired[bool]
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
class SetupPaymentFreeTrialParams(BaseModel):
r"""Free trial configuration for a plan."""
duration_length: float
r"""Number of duration_type periods the trial lasts."""
duration_type: Optional[SetupPaymentDurationType] = "month"
r"""Unit of time for the trial ('day', 'month', 'year')."""
card_required: Optional[bool] = True
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["duration_type", "card_required"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class SetupPaymentCustomizeTypedDict(TypedDict):
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
price: NotRequired[Nullable[SetupPaymentBasePriceTypedDict]]
r"""Override the base price of the plan. Pass null to remove the base price."""
items: NotRequired[List[SetupPaymentPlanItemTypedDict]]
r"""Override the items in the plan."""
free_trial: NotRequired[Nullable[SetupPaymentFreeTrialParamsTypedDict]]
r"""Override the plan's default free trial. Pass an object to set a custom trial, or null to remove the trial entirely."""
class SetupPaymentCustomize(BaseModel):
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
price: OptionalNullable[SetupPaymentBasePrice] = UNSET
r"""Override the base price of the plan. Pass null to remove the base price."""
items: Optional[List[SetupPaymentPlanItem]] = None
r"""Override the items in the plan."""
free_trial: OptionalNullable[SetupPaymentFreeTrialParams] = UNSET
r"""Override the plan's default free trial. Pass an object to set a custom trial, or null to remove the trial entirely."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["price", "items", "free_trial"])
nullable_fields = set(["price", "free_trial"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
SetupPaymentProrationBehavior = Literal[
"prorate_immediately",
"none",
]
r"""How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges."""
class SetupPaymentAttachDiscountTypedDict(TypedDict):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: NotRequired[str]
r"""The ID of the reward to apply as a discount."""
promotion_code: NotRequired[str]
r"""The promotion code to apply as a discount."""
class SetupPaymentAttachDiscount(BaseModel):
r"""A discount to apply. Can be either a reward ID or a promotion code."""
reward_id: Optional[str] = None
r"""The ID of the reward to apply as a discount."""
promotion_code: Optional[str] = None
r"""The promotion code to apply as a discount."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["reward_id", "promotion_code"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class SetupPaymentParamsTypedDict(TypedDict):
customer_id: str
r"""The ID of the customer to attach the plan to."""
entity_id: NotRequired[str]
r"""The ID of the entity to attach the plan to."""
plan_id: NotRequired[str]
r"""If specified, the plan will be attached to the customer after setup."""
feature_quantities: NotRequired[List[SetupPaymentFeatureQuantityTypedDict]]
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan."""
version: NotRequired[float]
r"""The version of the plan to attach."""
customize: NotRequired[SetupPaymentCustomizeTypedDict]
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
proration_behavior: NotRequired[SetupPaymentProrationBehavior]
r"""How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges."""
discounts: NotRequired[List[SetupPaymentAttachDiscountTypedDict]]
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: NotRequired[str]
r"""URL to redirect to after successful checkout."""
checkout_session_params: NotRequired[Dict[str, Any]]
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
class SetupPaymentParams(BaseModel):
customer_id: str
r"""The ID of the customer to attach the plan to."""
entity_id: Optional[str] = None
r"""The ID of the entity to attach the plan to."""
plan_id: Optional[str] = None
r"""If specified, the plan will be attached to the customer after setup."""
feature_quantities: Optional[List[SetupPaymentFeatureQuantity]] = None
r"""If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan."""
version: Optional[float] = None
r"""The version of the plan to attach."""
customize: Optional[SetupPaymentCustomize] = None
r"""Customize the plan to attach. Can override the price, items, free trial, or a combination."""
proration_behavior: Optional[SetupPaymentProrationBehavior] = None
r"""How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges."""
discounts: Optional[List[SetupPaymentAttachDiscount]] = None
r"""List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code."""
success_url: Optional[str] = None
r"""URL to redirect to after successful checkout."""
checkout_session_params: Optional[Dict[str, Any]] = None
r"""Additional parameters to pass into the creation of the Stripe checkout session."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
[
"entity_id",
"plan_id",
"feature_quantities",
"version",
"customize",
"proration_behavior",
"discounts",
"success_url",
"checkout_session_params",
]
)
serialized = handler(self)
m = {}
@@ -87,7 +699,9 @@ class SetupPaymentResponseTypedDict(TypedDict):
customer_id: str
r"""The ID of the customer"""
url: str
r"""URL to the payment setup page"""
r"""URL to redirect the customer to setup their payment."""
entity_id: NotRequired[str]
r"""The ID of the entity the plan (if specified) will be attached to after setup."""
class SetupPaymentResponse(BaseModel):
@@ -97,4 +711,23 @@ class SetupPaymentResponse(BaseModel):
r"""The ID of the customer"""
url: str
r"""URL to the payment setup page"""
r"""URL to redirect the customer to setup their payment."""
entity_id: Optional[str] = None
r"""The ID of the entity the plan (if specified) will be attached to after setup."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["entity_id"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m

View File

@@ -62,6 +62,8 @@ class UpdateBalanceParamsTypedDict(TypedDict):
r"""Set the remaining balance to this exact value. Cannot be combined with add_to_balance."""
add_to_balance: NotRequired[float]
r"""Add this amount to the current balance. Use negative values to subtract. Cannot be combined with current_balance."""
usage: NotRequired[float]
r"""The usage amount to update. Cannot be combined with remaining or add_to_balance."""
interval: NotRequired[UpdateBalanceInterval]
r"""Target a specific balance by its reset interval. Use when the customer has multiple balances for the same feature with different reset intervals."""
@@ -82,12 +84,17 @@ class UpdateBalanceParams(BaseModel):
add_to_balance: Optional[float] = None
r"""Add this amount to the current balance. Use negative values to subtract. Cannot be combined with current_balance."""
usage: Optional[float] = None
r"""The usage amount to update. Cannot be combined with remaining or add_to_balance."""
interval: Optional[UpdateBalanceInterval] = None
r"""Target a specific balance by its reset interval. Use when the customer has multiple balances for the same feature with different reset intervals."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["entity_id", "remaining", "add_to_balance", "interval"])
optional_fields = set(
["entity_id", "remaining", "add_to_balance", "usage", "interval"]
)
serialized = handler(self)
m = {}

View File

@@ -155,6 +155,7 @@ UpdatePlanToRequest = TypeAliasType("UpdatePlanToRequest", Union[float, str])
class UpdatePlanTierRequestTypedDict(TypedDict):
to: UpdatePlanToRequestTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class UpdatePlanTierRequest(BaseModel):
@@ -162,6 +163,39 @@ class UpdatePlanTierRequest(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
UpdatePlanTierBehaviorRequest = Literal[
"graduated",
"volume",
]
UpdatePlanItemPriceIntervalRequest = Literal[
"one_off",
@@ -191,7 +225,8 @@ class UpdatePlanPriceRequestTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: NotRequired[List[UpdatePlanTierRequestTypedDict]]
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: NotRequired[UpdatePlanTierBehaviorRequest]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
billing_units: NotRequired[float]
@@ -213,7 +248,9 @@ class UpdatePlanPriceRequest(BaseModel):
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
tiers: Optional[List[UpdatePlanTierRequest]] = None
r"""Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required."""
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
tier_behavior: Optional[UpdatePlanTierBehaviorRequest] = None
interval_count: Optional[float] = 1
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -227,7 +264,14 @@ class UpdatePlanPriceRequest(BaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
["amount", "tiers", "interval_count", "billing_units", "max_purchase"]
[
"amount",
"tiers",
"tier_behavior",
"interval_count",
"billing_units",
"max_purchase",
]
)
serialized = handler(self)
m = {}
@@ -792,6 +836,7 @@ UpdatePlanToResponse = TypeAliasType("UpdatePlanToResponse", Union[float, str])
class UpdatePlanTierResponseTypedDict(TypedDict):
to: UpdatePlanToResponseTypedDict
amount: float
flat_amount: NotRequired[Nullable[float]]
class UpdatePlanTierResponse(BaseModel):
@@ -799,6 +844,42 @@ class UpdatePlanTierResponse(BaseModel):
amount: float
flat_amount: OptionalNullable[float] = UNSET
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["flat_amount"])
nullable_fields = set(["flat_amount"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
is_nullable_and_explicitly_set = (
k in nullable_fields
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
)
if val != UNSET_SENTINEL:
if (
val is not None
or k not in optional_fields
or is_nullable_and_explicitly_set
):
m[k] = val
return m
UpdatePlanTierBehaviorResponse = Union[
Literal[
"graduated",
"volume",
],
UnrecognizedStr,
]
UpdatePlanPriceItemIntervalResponse = Union[
Literal[
@@ -836,7 +917,8 @@ class UpdatePlanItemPriceResponseTypedDict(TypedDict):
amount: NotRequired[float]
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: NotRequired[List[UpdatePlanTierResponseTypedDict]]
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: NotRequired[UpdatePlanTierBehaviorResponse]
interval_count: NotRequired[float]
r"""Number of intervals per billing cycle. Defaults to 1."""
@@ -858,14 +940,16 @@ class UpdatePlanItemPriceResponse(BaseModel):
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
tiers: Optional[List[UpdatePlanTierResponse]] = None
r"""Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required."""
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
tier_behavior: Optional[UpdatePlanTierBehaviorResponse] = None
interval_count: Optional[float] = None
r"""Number of intervals per billing cycle. Defaults to 1."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["amount", "tiers", "interval_count"])
optional_fields = set(["amount", "tiers", "tier_behavior", "interval_count"])
nullable_fields = set(["max_purchase"])
serialized = handler(self)
m = {}
@@ -1098,6 +1182,54 @@ UpdatePlanEnv = Union[
r"""Environment this plan belongs to ('sandbox' or 'live')."""
UpdatePlanScenario = Union[
Literal[
"scheduled",
"active",
"new",
"renew",
"upgrade",
"downgrade",
"cancel",
"expired",
"past_due",
],
UnrecognizedStr,
]
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
class UpdatePlanCustomerEligibilityTypedDict(TypedDict):
scenario: UpdatePlanScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: NotRequired[bool]
r"""Whether a free trial is available for this customer."""
class UpdatePlanCustomerEligibility(BaseModel):
scenario: UpdatePlanScenario
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
trial_available: Optional[bool] = None
r"""Whether a free trial is available for this customer."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["trial_available"])
serialized = handler(self)
m = {}
for n, f in type(self).model_fields.items():
k = f.alias or n
val = serialized.get(k)
if val != UNSET_SENTINEL:
if val is not None or k not in optional_fields:
m[k] = val
return m
class UpdatePlanResponseTypedDict(TypedDict):
r"""A plan defines a set of features, pricing, and entitlements that can be attached to customers."""
@@ -1129,6 +1261,7 @@ class UpdatePlanResponseTypedDict(TypedDict):
r"""If this is a variant, the ID of the base plan it was created from."""
free_trial: NotRequired[UpdatePlanFreeTrialTypedDict]
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: NotRequired[UpdatePlanCustomerEligibilityTypedDict]
class UpdatePlanResponse(BaseModel):
@@ -1176,9 +1309,11 @@ class UpdatePlanResponse(BaseModel):
free_trial: Optional[UpdatePlanFreeTrial] = None
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
customer_eligibility: Optional[UpdatePlanCustomerEligibility] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["free_trial"])
optional_fields = set(["free_trial", "customer_eligibility"])
nullable_fields = set(["description", "group", "price", "base_variant_id"])
serialized = handler(self)
m = {}

View File

@@ -1,7 +1,7 @@
{
"name": "autumn-js",
"description": "Autumn JS Library",
"version": "1.0.0-beta.5",
"version": "1.0.0-beta.6",
"repository": "github:useautumn/autumn",
"homepage": "https://docs.useautumn.com",
"main": "./dist/sdk/index.js",

View File

@@ -84,6 +84,18 @@ export const routeConfigs: RouteDefinition<RouteName>[] = [
sdkMethod: (autumn, args) => autumn.referrals.redeemCode(args),
bodySchema: redeemReferralCodeParamsSchema,
},
{
route: "multiAttach",
sdkMethod: (autumn, args) => autumn.billing.multiAttach(args),
},
{
route: "previewMultiAttach",
sdkMethod: (autumn, args) => autumn.billing.previewMultiAttach(args),
},
{
route: "setupPayment",
sdkMethod: (autumn, args) => autumn.billing.setupPayment(args),
},
{
route: "listPlans",
sdkMethod: (autumn, args) => autumn.plans.list(args),

View File

@@ -16,6 +16,9 @@ export const ROUTE_NAMES = {
listPlans: "listPlans",
listEvents: "listEvents",
aggregateEvents: "aggregateEvents",
multiAttach: "multiAttach",
previewMultiAttach: "previewMultiAttach",
setupPayment: "setupPayment",
} as const;
/** Union of all route names */

View File

@@ -47,6 +47,9 @@ export function autumn(options: AutumnOptions = {}): AutumnPlugin {
listPlans: createAutumnEndpoint("listPlans", handleRoute),
listEvents: createAutumnEndpoint("listEvents", handleRoute),
aggregateEvents: createAutumnEndpoint("aggregateEvents", handleRoute),
multiAttach: createAutumnEndpoint("multiAttach", handleRoute),
previewMultiAttach: createAutumnEndpoint("previewMultiAttach", handleRoute),
setupPayment: createAutumnEndpoint("setupPayment", handleRoute),
};
return {

View File

@@ -0,0 +1,276 @@
// Generated by ts-to-zod
import { z } from "zod/v4";
export const attachGlobalsSchema = z.object({
xApiVersion: z.union([z.string(), z.undefined()]).optional(),
});
export const attachFeatureQuantitySchema = z.object({
featureId: z.string(),
quantity: z.union([z.number(), z.undefined()]).optional(),
adjustable: z.union([z.boolean(), z.undefined()]).optional(),
});
export const attachToSchema = z.union([z.number(), z.string()]);
export const attachTierSchema = z.object({
to: z.union([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.union([z.number(), z.undefined()]).optional().nullable(),
});
export const attachInvoiceModeSchema = z.object({
enabled: z.boolean(),
enablePlanImmediately: z.union([z.boolean(), z.undefined()]).optional(),
finalize: z.union([z.boolean(), z.undefined()]).optional(),
});
export const attachAttachDiscountSchema = z.object({
rewardId: z.union([z.string(), z.undefined()]).optional(),
promotionCode: z.union([z.string(), z.undefined()]).optional(),
});
export const attachInvoiceSchema = z.object({
status: z.string().nullable(),
stripeId: z.string(),
total: z.number(),
currency: z.string(),
hostedInvoiceUrl: z.string().nullable(),
});
export const attachFeatureQuantityOutboundSchema = z.object({
feature_id: z.string(),
quantity: z.union([z.number(), z.undefined()]).optional(),
adjustable: z.union([z.boolean(), z.undefined()]).optional(),
});
export const attachBasePriceOutboundSchema = z.object({
amount: z.number(),
interval: z.string(),
interval_count: z.union([z.number(), z.undefined()]).optional(),
});
export const attachResetOutboundSchema = z.object({
interval: z.string(),
interval_count: z.union([z.number(), z.undefined()]).optional(),
});
export const attachToOutboundSchema = z.union([z.number(), z.string()]);
export const attachTierOutboundSchema = z.object({
to: z.union([z.number(), z.string()]),
amount: z.number(),
flat_amount: z.union([z.number(), z.undefined()]).optional().nullable(),
});
export const attachPriceOutboundSchema = z.object({
amount: z.union([z.number(), z.undefined()]).optional(),
tiers: z.union([z.array(attachTierOutboundSchema), z.undefined()]).optional(),
tier_behavior: z.union([z.string(), z.undefined()]).optional(),
interval: z.string(),
interval_count: z.number(),
billing_units: z.number(),
billing_method: z.string(),
max_purchase: z.union([z.number(), z.undefined()]).optional(),
});
export const attachProrationOutboundSchema = z.object({
on_increase: z.string(),
on_decrease: z.string(),
});
export const attachRolloverOutboundSchema = z.object({
max: z.union([z.number(), z.undefined()]).optional(),
expiry_duration_type: z.string(),
expiry_duration_length: z.union([z.number(), z.undefined()]).optional(),
});
export const attachPlanItemOutboundSchema = z.object({
feature_id: z.string(),
included: z.union([z.number(), z.undefined()]).optional(),
unlimited: z.union([z.boolean(), z.undefined()]).optional(),
reset: z.union([attachResetOutboundSchema, z.undefined()]).optional(),
price: z.union([attachPriceOutboundSchema, z.undefined()]).optional(),
proration: z.union([attachProrationOutboundSchema, z.undefined()]).optional(),
rollover: z.union([attachRolloverOutboundSchema, z.undefined()]).optional(),
});
export const attachFreeTrialParamsOutboundSchema = z.object({
duration_length: z.number(),
duration_type: z.string(),
card_required: z.boolean(),
});
export const attachCustomizeOutboundSchema = z.object({
price: z
.union([attachBasePriceOutboundSchema, z.undefined()])
.optional()
.nullable(),
items: z
.union([z.array(attachPlanItemOutboundSchema), z.undefined()])
.optional(),
free_trial: z
.union([attachFreeTrialParamsOutboundSchema, z.undefined()])
.optional()
.nullable(),
});
export const attachInvoiceModeOutboundSchema = z.object({
enabled: z.boolean(),
enable_plan_immediately: z.boolean(),
finalize: z.boolean(),
});
export const attachAttachDiscountOutboundSchema = z.object({
reward_id: z.union([z.string(), z.undefined()]).optional(),
promotion_code: z.union([z.string(), z.undefined()]).optional(),
});
export const attachParamsOutboundSchema = z.object({
customer_id: z.string(),
entity_id: z.union([z.string(), z.undefined()]).optional(),
plan_id: z.string(),
feature_quantities: z
.union([z.array(attachFeatureQuantityOutboundSchema), z.undefined()])
.optional(),
version: z.union([z.number(), z.undefined()]).optional(),
customize: z.union([attachCustomizeOutboundSchema, z.undefined()]).optional(),
invoice_mode: z
.union([attachInvoiceModeOutboundSchema, z.undefined()])
.optional(),
proration_behavior: z.union([z.string(), z.undefined()]).optional(),
discounts: z
.union([z.array(attachAttachDiscountOutboundSchema), z.undefined()])
.optional(),
success_url: z.union([z.string(), z.undefined()]).optional(),
new_billing_subscription: z.union([z.boolean(), z.undefined()]).optional(),
plan_schedule: z.union([z.string(), z.undefined()]).optional(),
checkout_session_params: z
.union([z.record(z.string(), z.any()), z.undefined()])
.optional(),
});
const closedEnumSchema = z.any();
const openEnumSchema = z.any();
export const attachPriceIntervalSchema = closedEnumSchema;
export const attachBasePriceSchema = z.object({
amount: z.number(),
interval: attachPriceIntervalSchema,
intervalCount: z.union([z.number(), z.undefined()]).optional(),
});
export const attachResetIntervalSchema = closedEnumSchema;
export const attachResetSchema = z.object({
interval: attachResetIntervalSchema,
intervalCount: z.union([z.number(), z.undefined()]).optional(),
});
export const attachTierBehaviorSchema = closedEnumSchema;
export const attachItemPriceIntervalSchema = closedEnumSchema;
export const attachBillingMethodSchema = closedEnumSchema;
export const attachPriceSchema = z.object({
amount: z.union([z.number(), z.undefined()]).optional(),
tiers: z.union([z.array(attachTierSchema), z.undefined()]).optional(),
tierBehavior: z.union([attachTierBehaviorSchema, z.undefined()]).optional(),
interval: attachItemPriceIntervalSchema,
intervalCount: z.union([z.number(), z.undefined()]).optional(),
billingUnits: z.union([z.number(), z.undefined()]).optional(),
billingMethod: attachBillingMethodSchema,
maxPurchase: z.union([z.number(), z.undefined()]).optional(),
});
export const attachOnIncreaseSchema = closedEnumSchema;
export const attachOnDecreaseSchema = closedEnumSchema;
export const attachProrationSchema = z.object({
onIncrease: attachOnIncreaseSchema,
onDecrease: attachOnDecreaseSchema,
});
export const attachExpiryDurationTypeSchema = closedEnumSchema;
export const attachRolloverSchema = z.object({
max: z.union([z.number(), z.undefined()]).optional(),
expiryDurationType: attachExpiryDurationTypeSchema,
expiryDurationLength: z.union([z.number(), z.undefined()]).optional(),
});
export const attachPlanItemSchema = z.object({
featureId: z.string(),
included: z.union([z.number(), z.undefined()]).optional(),
unlimited: z.union([z.boolean(), z.undefined()]).optional(),
reset: z.union([attachResetSchema, z.undefined()]).optional(),
price: z.union([attachPriceSchema, z.undefined()]).optional(),
proration: z.union([attachProrationSchema, z.undefined()]).optional(),
rollover: z.union([attachRolloverSchema, z.undefined()]).optional(),
});
export const attachDurationTypeSchema = closedEnumSchema;
export const attachFreeTrialParamsSchema = z.object({
durationLength: z.number(),
durationType: z.union([attachDurationTypeSchema, z.undefined()]).optional(),
cardRequired: z.union([z.boolean(), z.undefined()]).optional(),
});
export const attachCustomizeSchema = z.object({
price: z.union([attachBasePriceSchema, z.undefined()]).optional().nullable(),
items: z.union([z.array(attachPlanItemSchema), z.undefined()]).optional(),
freeTrial: z
.union([attachFreeTrialParamsSchema, z.undefined()])
.optional()
.nullable(),
});
export const attachProrationBehaviorSchema = closedEnumSchema;
export const attachPlanScheduleSchema = closedEnumSchema;
export const attachParamsSchema = z.object({
customerId: z.string(),
entityId: z.union([z.string(), z.undefined()]).optional(),
planId: z.string(),
featureQuantities: z
.union([z.array(attachFeatureQuantitySchema), z.undefined()])
.optional(),
version: z.union([z.number(), z.undefined()]).optional(),
customize: z.union([attachCustomizeSchema, z.undefined()]).optional(),
invoiceMode: z.union([attachInvoiceModeSchema, z.undefined()]).optional(),
prorationBehavior: z
.union([attachProrationBehaviorSchema, z.undefined()])
.optional(),
discounts: z
.union([z.array(attachAttachDiscountSchema), z.undefined()])
.optional(),
successUrl: z.union([z.string(), z.undefined()]).optional(),
newBillingSubscription: z.union([z.boolean(), z.undefined()]).optional(),
planSchedule: z.union([attachPlanScheduleSchema, z.undefined()]).optional(),
checkoutSessionParams: z
.union([z.record(z.string(), z.any()), z.undefined()])
.optional(),
});
export const attachCodeSchema = openEnumSchema;
export const attachRequiredActionSchema = z.object({
code: attachCodeSchema,
reason: z.string(),
});
export const attachResponseSchema = z.object({
customerId: z.string(),
entityId: z.union([z.string(), z.undefined()]).optional(),
invoice: z.union([attachInvoiceSchema, z.undefined()]).optional(),
paymentUrl: z.string().nullable(),
requiredAction: z
.union([attachRequiredActionSchema, z.undefined()])
.optional(),
});

View File

@@ -1,283 +0,0 @@
// Generated by ts-to-zod
import { z } from "zod/v4";
export const billingAttachGlobalsSchema = z.object({
xApiVersion: z.union([z.string(), z.undefined()]).optional(),
});
export const billingAttachFeatureQuantitySchema = z.object({
featureId: z.string(),
quantity: z.union([z.number(), z.undefined()]).optional(),
adjustable: z.union([z.boolean(), z.undefined()]).optional(),
});
export const billingAttachToSchema = z.union([z.number(), z.string()]);
export const billingAttachTierSchema = z.object({
to: z.union([z.number(), z.string()]),
amount: z.number(),
});
export const billingAttachInvoiceModeSchema = z.object({
enabled: z.boolean(),
enablePlanImmediately: z.union([z.boolean(), z.undefined()]).optional(),
finalize: z.union([z.boolean(), z.undefined()]).optional(),
});
export const billingAttachAttachDiscountSchema = z.object({
rewardId: z.union([z.string(), z.undefined()]).optional(),
promotionCode: z.union([z.string(), z.undefined()]).optional(),
});
export const billingAttachInvoiceSchema = z.object({
status: z.string().nullable(),
stripeId: z.string(),
total: z.number(),
currency: z.string(),
hostedInvoiceUrl: z.string().nullable(),
});
export const billingAttachFeatureQuantityOutboundSchema = z.object({
feature_id: z.string(),
quantity: z.union([z.number(), z.undefined()]).optional(),
adjustable: z.union([z.boolean(), z.undefined()]).optional(),
});
export const billingAttachBasePriceOutboundSchema = z.object({
amount: z.number(),
interval: z.string(),
interval_count: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachResetOutboundSchema = z.object({
interval: z.string(),
interval_count: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachToOutboundSchema = z.union([z.number(), z.string()]);
export const billingAttachTierOutboundSchema = z.object({
to: z.union([z.number(), z.string()]),
amount: z.number(),
});
export const billingAttachPriceOutboundSchema = z.object({
amount: z.union([z.number(), z.undefined()]).optional(),
tiers: z
.union([z.array(billingAttachTierOutboundSchema), z.undefined()])
.optional(),
interval: z.string(),
interval_count: z.number(),
billing_units: z.number(),
billing_method: z.string(),
max_purchase: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachProrationOutboundSchema = z.object({
on_increase: z.string(),
on_decrease: z.string(),
});
export const billingAttachRolloverOutboundSchema = z.object({
max: z.union([z.number(), z.undefined()]).optional(),
expiry_duration_type: z.string(),
expiry_duration_length: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachPlanItemOutboundSchema = z.object({
feature_id: z.string(),
included: z.union([z.number(), z.undefined()]).optional(),
unlimited: z.union([z.boolean(), z.undefined()]).optional(),
reset: z.union([billingAttachResetOutboundSchema, z.undefined()]).optional(),
price: z.union([billingAttachPriceOutboundSchema, z.undefined()]).optional(),
proration: z
.union([billingAttachProrationOutboundSchema, z.undefined()])
.optional(),
rollover: z
.union([billingAttachRolloverOutboundSchema, z.undefined()])
.optional(),
});
export const billingAttachFreeTrialParamsOutboundSchema = z.object({
duration_length: z.number(),
duration_type: z.string(),
card_required: z.boolean(),
});
export const billingAttachCustomizeOutboundSchema = z.object({
price: z
.union([billingAttachBasePriceOutboundSchema, z.undefined()])
.optional()
.nullable(),
items: z
.union([z.array(billingAttachPlanItemOutboundSchema), z.undefined()])
.optional(),
free_trial: z
.union([billingAttachFreeTrialParamsOutboundSchema, z.undefined()])
.optional()
.nullable(),
});
export const billingAttachInvoiceModeOutboundSchema = z.object({
enabled: z.boolean(),
enable_plan_immediately: z.boolean(),
finalize: z.boolean(),
});
export const billingAttachAttachDiscountOutboundSchema = z.object({
reward_id: z.union([z.string(), z.undefined()]).optional(),
promotion_code: z.union([z.string(), z.undefined()]).optional(),
});
export const attachParamsOutboundSchema = z.object({
customer_id: z.string(),
entity_id: z.union([z.string(), z.undefined()]).optional(),
plan_id: z.string(),
feature_quantities: z
.union([z.array(billingAttachFeatureQuantityOutboundSchema), z.undefined()])
.optional(),
version: z.union([z.number(), z.undefined()]).optional(),
customize: z
.union([billingAttachCustomizeOutboundSchema, z.undefined()])
.optional(),
invoice_mode: z
.union([billingAttachInvoiceModeOutboundSchema, z.undefined()])
.optional(),
proration_behavior: z.union([z.string(), z.undefined()]).optional(),
discounts: z
.union([z.array(billingAttachAttachDiscountOutboundSchema), z.undefined()])
.optional(),
success_url: z.union([z.string(), z.undefined()]).optional(),
new_billing_subscription: z.union([z.boolean(), z.undefined()]).optional(),
plan_schedule: z.union([z.string(), z.undefined()]).optional(),
});
const closedEnumSchema = z.any();
const openEnumSchema = z.any();
export const billingAttachPriceIntervalSchema = closedEnumSchema;
export const billingAttachBasePriceSchema = z.object({
amount: z.number(),
interval: billingAttachPriceIntervalSchema,
intervalCount: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachResetIntervalSchema = closedEnumSchema;
export const billingAttachResetSchema = z.object({
interval: billingAttachResetIntervalSchema,
intervalCount: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachItemPriceIntervalSchema = closedEnumSchema;
export const billingAttachBillingMethodSchema = closedEnumSchema;
export const billingAttachPriceSchema = z.object({
amount: z.union([z.number(), z.undefined()]).optional(),
tiers: z.union([z.array(billingAttachTierSchema), z.undefined()]).optional(),
interval: billingAttachItemPriceIntervalSchema,
intervalCount: z.union([z.number(), z.undefined()]).optional(),
billingUnits: z.union([z.number(), z.undefined()]).optional(),
billingMethod: billingAttachBillingMethodSchema,
maxPurchase: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachOnIncreaseSchema = closedEnumSchema;
export const billingAttachOnDecreaseSchema = closedEnumSchema;
export const billingAttachProrationSchema = z.object({
onIncrease: billingAttachOnIncreaseSchema,
onDecrease: billingAttachOnDecreaseSchema,
});
export const billingAttachExpiryDurationTypeSchema = closedEnumSchema;
export const billingAttachRolloverSchema = z.object({
max: z.union([z.number(), z.undefined()]).optional(),
expiryDurationType: billingAttachExpiryDurationTypeSchema,
expiryDurationLength: z.union([z.number(), z.undefined()]).optional(),
});
export const billingAttachPlanItemSchema = z.object({
featureId: z.string(),
included: z.union([z.number(), z.undefined()]).optional(),
unlimited: z.union([z.boolean(), z.undefined()]).optional(),
reset: z.union([billingAttachResetSchema, z.undefined()]).optional(),
price: z.union([billingAttachPriceSchema, z.undefined()]).optional(),
proration: z.union([billingAttachProrationSchema, z.undefined()]).optional(),
rollover: z.union([billingAttachRolloverSchema, z.undefined()]).optional(),
});
export const billingAttachDurationTypeSchema = closedEnumSchema;
export const billingAttachFreeTrialParamsSchema = z.object({
durationLength: z.number(),
durationType: z
.union([billingAttachDurationTypeSchema, z.undefined()])
.optional(),
cardRequired: z.union([z.boolean(), z.undefined()]).optional(),
});
export const billingAttachCustomizeSchema = z.object({
price: z
.union([billingAttachBasePriceSchema, z.undefined()])
.optional()
.nullable(),
items: z
.union([z.array(billingAttachPlanItemSchema), z.undefined()])
.optional(),
freeTrial: z
.union([billingAttachFreeTrialParamsSchema, z.undefined()])
.optional()
.nullable(),
});
export const billingAttachProrationBehaviorSchema = closedEnumSchema;
export const billingAttachPlanScheduleSchema = closedEnumSchema;
export const attachParamsSchema = z.object({
customerId: z.string(),
entityId: z.union([z.string(), z.undefined()]).optional(),
planId: z.string(),
featureQuantities: z
.union([z.array(billingAttachFeatureQuantitySchema), z.undefined()])
.optional(),
version: z.union([z.number(), z.undefined()]).optional(),
customize: z.union([billingAttachCustomizeSchema, z.undefined()]).optional(),
invoiceMode: z
.union([billingAttachInvoiceModeSchema, z.undefined()])
.optional(),
prorationBehavior: z
.union([billingAttachProrationBehaviorSchema, z.undefined()])
.optional(),
discounts: z
.union([z.array(billingAttachAttachDiscountSchema), z.undefined()])
.optional(),
successUrl: z.union([z.string(), z.undefined()]).optional(),
newBillingSubscription: z.union([z.boolean(), z.undefined()]).optional(),
planSchedule: z
.union([billingAttachPlanScheduleSchema, z.undefined()])
.optional(),
});
export const billingAttachCodeSchema = openEnumSchema;
export const billingAttachRequiredActionSchema = z.object({
code: billingAttachCodeSchema,
reason: z.string(),
});
export const billingAttachResponseSchema = z.object({
customerId: z.string(),
entityId: z.union([z.string(), z.undefined()]).optional(),
invoice: z.union([billingAttachInvoiceSchema, z.undefined()]).optional(),
paymentUrl: z.string().nullable(),
requiredAction: z
.union([billingAttachRequiredActionSchema, z.undefined()])
.optional(),
});

View File

@@ -2,7 +2,7 @@
// Run `bun api` to regenerate
export * from "./aggregateEventsSchemas";
export * from "./billingAttachSchemas";
export * from "./attachSchemas";
export * from "./createReferralCodeSchemas";
export * from "./getOrCreateCustomerSchemas";
export * from "./listEventsSchemas";

View File

@@ -31,6 +31,7 @@ export const listPlansToSchema = z.union([z.number(), z.string()]);
export const listPlansTierSchema = z.object({
to: z.union([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.union([z.number(), z.undefined()]).optional().nullable(),
});
export const listPlansItemDisplaySchema = z.object({
@@ -79,6 +80,8 @@ export const listPlansResetSchema = z.object({
intervalCount: z.union([z.number(), z.undefined()]).optional(),
});
export const listPlansTierBehaviorSchema = openEnumSchema;
export const listPlansPriceItemIntervalSchema = openEnumSchema;
export const listPlansBillingMethodSchema = openEnumSchema;
@@ -86,6 +89,9 @@ export const listPlansBillingMethodSchema = openEnumSchema;
export const listPlansItemPriceSchema = z.object({
amount: z.union([z.number(), z.undefined()]).optional(),
tiers: z.union([z.array(listPlansTierSchema), z.undefined()]).optional(),
tierBehavior: z
.union([listPlansTierBehaviorSchema, z.undefined()])
.optional(),
interval: listPlansPriceItemIntervalSchema,
intervalCount: z.union([z.number(), z.undefined()]).optional(),
billingUnits: z.number(),
@@ -122,6 +128,13 @@ export const listPlansFreeTrialSchema = z.object({
export const listPlansEnvSchema = openEnumSchema;
export const listPlansScenarioSchema = openEnumSchema;
export const listPlansCustomerEligibilitySchema = z.object({
trialAvailable: z.union([z.boolean(), z.undefined()]).optional(),
scenario: listPlansScenarioSchema,
});
export const listPlansListSchema = z.object({
id: z.string(),
name: z.string(),
@@ -137,6 +150,9 @@ export const listPlansListSchema = z.object({
env: listPlansEnvSchema,
archived: z.boolean(),
baseVariantId: z.string().nullable(),
customerEligibility: z
.union([listPlansCustomerEligibilitySchema, z.undefined()])
.optional(),
});
export const listPlansResponseSchema = z.object({

View File

@@ -1,15 +1,18 @@
import type {
AggregateEventsResponse,
BillingAttachResponse,
AttachResponse,
BillingUpdateResponse,
CreateReferralCodeResponse,
Customer,
ListEventsResponse,
ListPlansResponse,
MultiAttachResponse,
OpenCustomerPortalResponse,
PreviewAttachResponse,
PreviewMultiAttachResponse,
PreviewUpdateResponse,
RedeemReferralCodeResponse,
SetupPaymentResponse,
} from "@useautumn/sdk";
import type { IAutumnClient } from "./IAutumnClient";
import { createHttpClient } from "./internal/httpClient";
@@ -37,7 +40,7 @@ export const createAutumnClient = (
body: params,
}),
attach: (params) =>
http.request<BillingAttachResponse>({
http.request<AttachResponse>({
route: "attach",
body: params,
}),
@@ -56,6 +59,21 @@ export const createAutumnClient = (
route: "previewUpdateSubscription",
body: params,
}),
multiAttach: (params) =>
http.request<MultiAttachResponse>({
route: "multiAttach",
body: params,
}),
previewMultiAttach: (params) =>
http.request<PreviewMultiAttachResponse>({
route: "previewMultiAttach",
body: params,
}),
setupPayment: (params) =>
http.request<SetupPaymentResponse>({
route: "setupPayment",
body: params,
}),
openCustomerPortal: (params) =>
http.request<OpenCustomerPortalResponse>({
route: "openCustomerPortal",

View File

@@ -1,6 +1,7 @@
import type {
AggregateEventsResponse,
BillingAttachResponse,
AttachResponse,
MultiAttachResponse,
BillingUpdateResponse,
CreateReferralCodeResponse,
Customer,
@@ -8,8 +9,10 @@ import type {
ListPlansResponse,
OpenCustomerPortalResponse,
PreviewAttachResponse,
PreviewMultiAttachResponse,
PreviewUpdateResponse,
RedeemReferralCodeResponse,
SetupPaymentResponse,
} from "@useautumn/sdk";
import type {
AggregateEventsParams,
@@ -17,10 +20,13 @@ import type {
CreateReferralCodeParams,
GetOrCreateCustomerClientParams,
ListEventsParams,
MultiAttachParams,
OpenCustomerPortalParams,
PreviewAttachParams,
PreviewMultiAttachParams,
PreviewUpdateSubscriptionParams,
RedeemReferralCodeParams,
SetupPaymentParams,
UpdateSubscriptionParams,
} from "../../types";
@@ -29,7 +35,7 @@ export interface IAutumnClient {
getOrCreateCustomer: (
params?: GetOrCreateCustomerClientParams,
) => Promise<Customer | null>;
attach: (params: AttachParams) => Promise<BillingAttachResponse>;
attach: (params: AttachParams) => Promise<AttachResponse>;
previewAttach: (
params: PreviewAttachParams,
) => Promise<PreviewAttachResponse>;
@@ -39,6 +45,13 @@ export interface IAutumnClient {
previewUpdateSubscription: (
params: PreviewUpdateSubscriptionParams,
) => Promise<PreviewUpdateResponse>;
multiAttach: (
params: MultiAttachParams,
) => Promise<MultiAttachResponse>;
previewMultiAttach: (
params: PreviewMultiAttachParams,
) => Promise<PreviewMultiAttachResponse>;
setupPayment: (params: SetupPaymentParams) => Promise<SetupPaymentResponse>;
openCustomerPortal: (
params: OpenCustomerPortalParams,
) => Promise<OpenCustomerPortalResponse>;

View File

@@ -1,21 +1,27 @@
"use client";
import type {
BillingAttachResponse,
AttachResponse,
BillingUpdateResponse,
CheckResponse,
Customer,
MultiAttachResponse,
OpenCustomerPortalResponse,
PreviewAttachResponse,
PreviewMultiAttachResponse,
PreviewUpdateResponse,
SetupPaymentResponse,
} from "@useautumn/sdk";
import { useCallback } from "react";
import type {
AttachParams,
CheckParams,
MultiAttachParams,
OpenCustomerPortalParams,
PreviewAttachParams,
PreviewMultiAttachParams,
PreviewUpdateSubscriptionParams,
SetupPaymentParams,
UpdateSubscriptionParams,
} from "../../../types";
import type { IAutumnClient } from "../../client/IAutumnClient";
@@ -35,11 +41,6 @@ const redirectToUrl = ({
}
};
type SetupPaymentParams = {
successUrl?: string;
openInNewTab?: boolean;
};
export const useCustomerActions = ({
client,
customer,
@@ -48,7 +49,7 @@ export const useCustomerActions = ({
customer: Customer | null;
}) => {
const attach = useCallback(
async (params: AttachParams): Promise<BillingAttachResponse> => {
async (params: AttachParams): Promise<AttachResponse> => {
const response = await client.attach({
...params,
successUrl: params.successUrl ?? window.location.href,
@@ -127,20 +128,41 @@ export const useCustomerActions = ({
[client],
);
const setupPayment = useCallback(
async (params: SetupPaymentParams = {}) => {
const setupPaymentClient = client as IAutumnClient & {
setupPayment: (args: { successUrl?: string }) => Promise<{
paymentUrl?: string | null;
url?: string;
}>;
};
const response = await setupPaymentClient.setupPayment({
const multiAttach = useCallback(
async (params: MultiAttachParams): Promise<MultiAttachResponse> => {
const response = await client.multiAttach({
...params,
successUrl: params.successUrl ?? window.location.href,
});
const redirectUrl = response.url ?? response.paymentUrl;
if (response.paymentUrl) {
redirectToUrl({
url: response.paymentUrl,
openInNewTab: params.openInNewTab,
});
}
return response;
},
[client],
);
const previewMultiAttach = useCallback(
async (
params: PreviewMultiAttachParams,
): Promise<PreviewMultiAttachResponse> => {
return client.previewMultiAttach(params);
},
[client],
);
const setupPayment = useCallback(
async (params: SetupPaymentParams = {}): Promise<SetupPaymentResponse> => {
const response = await client.setupPayment({
...params,
successUrl: params.successUrl ?? window.location.href,
});
const redirectUrl = response.url;
if (redirectUrl) {
redirectToUrl({
url: redirectUrl,
@@ -158,6 +180,8 @@ export const useCustomerActions = ({
previewAttach,
updateSubscription,
previewUpdateSubscription,
multiAttach,
previewMultiAttach,
check,
openCustomerPortal,
setupPayment,
@@ -167,8 +191,10 @@ export const useCustomerActions = ({
export type {
AttachParams,
CheckParams,
MultiAttachParams,
OpenCustomerPortalParams,
PreviewAttachParams,
PreviewMultiAttachParams,
PreviewUpdateSubscriptionParams,
SetupPaymentParams,
UpdateSubscriptionParams,

View File

@@ -2,21 +2,27 @@
import { useQuery } from "@tanstack/react-query";
import type {
BillingAttachResponse,
AttachResponse,
BillingUpdateResponse,
CheckResponse,
Customer,
MultiAttachResponse,
OpenCustomerPortalResponse,
PreviewAttachResponse,
PreviewMultiAttachResponse,
PreviewUpdateResponse,
SetupPaymentResponse,
} from "@useautumn/sdk";
import type {
AttachParams,
CheckParams,
GetOrCreateCustomerClientParams,
MultiAttachParams,
OpenCustomerPortalParams,
PreviewAttachParams,
PreviewMultiAttachParams,
PreviewUpdateSubscriptionParams,
SetupPaymentParams,
UpdateSubscriptionParams,
} from "../../types";
import { useAutumnClient } from "../AutumnContext";
@@ -43,7 +49,7 @@ export type UseCustomerResult = HookResultWithMethods<
* @param params - Plan ID and optional configuration (free trial, custom pricing, discounts).
* @returns Billing response with customer ID, invoice details, and payment URL if checkout required.
*/
attach: (params: AttachParams) => Promise<BillingAttachResponse>;
attach: (params: AttachParams) => Promise<AttachResponse>;
/**
* Previews the billing changes that would occur when attaching a plan, without making any changes.
@@ -82,6 +88,33 @@ export type UseCustomerResult = HookResultWithMethods<
*/
check: (params: UseCustomerCheckParams) => CheckResponse;
/**
* Attaches multiple plans to the customer in one operation.
* Automatically redirects to checkout if payment is required.
* @param params - List of plans with optional feature quantities, free trial, and discounts.
* @returns Billing response with customer ID, invoice details, and payment URL if checkout required.
*/
multiAttach: (params: MultiAttachParams) => Promise<MultiAttachResponse>;
/**
* Previews the billing changes for attaching multiple plans, without making changes.
* @param params - List of plans with optional feature quantities to preview.
* @returns Preview with line items, totals, and effective dates for the proposed changes.
*/
previewMultiAttach: (
params: PreviewMultiAttachParams,
) => Promise<PreviewMultiAttachResponse>;
/**
* Creates a payment setup session for the customer to add or update their payment method.
* Automatically redirects to the Stripe setup page.
* @param params - Optional success URL and plan to attach after setup.
* @returns Setup response with URL to redirect the customer.
*/
setupPayment: (
params?: SetupPaymentParams,
) => Promise<SetupPaymentResponse>;
/**
* Opens the Stripe customer billing portal for this customer.
* @param params - Optional return URL and configuration.
@@ -96,7 +129,7 @@ export type UseCustomerResult = HookResultWithMethods<
/**
* Fetches or creates an Autumn customer and provides billing actions.
*
* @returns Customer data along with billing methods: `attach`, `previewAttach`, `updateSubscription`, `previewUpdateSubscription`, `check`, and `openCustomerPortal`.
* @returns Customer data along with billing methods: `attach`, `previewAttach`, `updateSubscription`, `previewUpdateSubscription`, `multiAttach`, `previewMultiAttach`, `check`, `setupPayment`, and `openCustomerPortal`.
*/
export const useCustomer = (
params: UseCustomerParams = {},

View File

@@ -7,10 +7,13 @@ export type {
ClientCreateReferralCodeParams,
ClientGetOrCreateCustomerParams,
ClientListEventsParams,
ClientMultiAttachParams,
ClientOpenCustomerPortalParams,
ClientPreviewAttachParams,
ClientPreviewMultiAttachParams,
ClientPreviewUpdateSubscriptionParams,
ClientRedeemReferralCodeParams,
ClientSetupPaymentParams,
ClientUpdateSubscriptionParams,
ProtectedFields,
} from "../types/params";

View File

@@ -5,10 +5,13 @@ export type {
ClientCreateReferralCodeParams as CreateReferralCodeParams,
ClientGetOrCreateCustomerParams as GetOrCreateCustomerClientParams,
ClientListEventsParams as ListEventsParams,
ClientMultiAttachParams as MultiAttachParams,
ClientOpenCustomerPortalParams as OpenCustomerPortalParams,
ClientPreviewAttachParams as PreviewAttachParams,
ClientPreviewMultiAttachParams as PreviewMultiAttachParams,
ClientPreviewUpdateSubscriptionParams as PreviewUpdateSubscriptionParams,
ClientRedeemReferralCodeParams as RedeemReferralCodeParams,
ClientSetupPaymentParams as SetupPaymentParams,
ClientUpdateSubscriptionParams as UpdateSubscriptionParams,
ProtectedFields,
} from "./params";

View File

@@ -5,13 +5,19 @@ import type {
CustomerExpand,
EventsAggregateParams,
EventsListParams,
MultiAttachParams,
OpenCustomerPortalParams,
PreviewAttachParams,
PreviewMultiAttachParams,
PreviewUpdateParams,
RedeemReferralCodeParams,
SetupPaymentParams,
UpdateSubscriptionParams,
} from "@useautumn/sdk";
/** Flattens Omit/Pick/intersection types so hover shows all fields */
type Prettify<T> = { [K in keyof T]: T[K] } & {};
/** Fields injected by backend - stripped from frontend params */
export type ProtectedFields = "customerId" | "customerData";
@@ -22,15 +28,17 @@ export type ClientGetOrCreateCustomerParams = {
};
/** Check params for local balance check */
export type ClientCheckParams = Omit<CheckParams, ProtectedFields>;
export type ClientCheckParams = Prettify<Omit<CheckParams, ProtectedFields>>;
/** Attach params without protected fields (for frontend use) */
export type ClientAttachParams = Omit<
AttachParams,
ProtectedFields | "sendEvent" | "properties" | "withPreview"
> & {
openInNewTab?: boolean;
};
export type ClientAttachParams = Prettify<
Omit<
AttachParams,
ProtectedFields | "sendEvent" | "properties" | "withPreview"
> & {
openInNewTab?: boolean;
}
>;
/** Open customer portal params without protected fields (for frontend use) */
export type ClientOpenCustomerPortalParams = Omit<
@@ -80,3 +88,25 @@ export type ClientPreviewUpdateSubscriptionParams = Omit<
PreviewUpdateParams,
ProtectedFields
>;
/** Multi-attach params without protected fields (for frontend use) */
export type ClientMultiAttachParams = Omit<
MultiAttachParams,
ProtectedFields
> & {
openInNewTab?: boolean;
};
/** Preview multi-attach params without protected fields (for frontend use) */
export type ClientPreviewMultiAttachParams = Omit<
PreviewMultiAttachParams,
ProtectedFields
>;
/** Setup payment params without protected fields (for frontend use) */
export type ClientSetupPaymentParams = Omit<
SetupPaymentParams,
ProtectedFields
> & {
openInNewTab?: boolean;
};

View File

@@ -672,11 +672,15 @@ components:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or 'amount' is
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount' is
required.
tier_behavior:
enum:
@@ -802,6 +806,27 @@ components:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -1000,6 +1025,10 @@ components:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
@@ -2006,11 +2035,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -2357,12 +2389,16 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount'
is required.
tier_behavior:
enum:
- graduated
@@ -2489,6 +2525,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -2786,12 +2843,16 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount'
is required.
tier_behavior:
enum:
- graduated
@@ -2918,6 +2979,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -3221,11 +3303,15 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or
'amount' is required.
tier_behavior:
enum:
@@ -3355,6 +3441,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -3549,11 +3656,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -3886,12 +3996,16 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount'
is required.
tier_behavior:
enum:
- graduated
@@ -4018,6 +4132,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -4778,7 +4913,7 @@ paths:
- *a5
/v1/billing.attach:
post:
operationId: billingAttach
operationId: attach
description: >-
Attaches a plan to a customer. Handles new subscriptions, upgrades and
downgrades.
@@ -4916,11 +5051,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -5191,7 +5329,7 @@ paths:
- *a5
/v1/billing.multi_attach:
post:
operationId: billingMultiAttach
operationId: multiAttach
description: >-
Attaches multiple plans to a customer in a single request. Creates a
single Stripe subscription with all plans consolidated.
@@ -5310,11 +5448,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -5767,11 +5908,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -6167,11 +6311,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -6625,11 +6772,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -7017,11 +7167,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -7464,11 +7617,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -8039,6 +8195,12 @@ paths:
amount:
type: number
description: The price of the product item for this tier.
flat_amount:
anyOf:
- type: number
- type: "null"
description: A flat fee charged for this tier, in addition to the per-unit
amount.
required:
- to
- amount

View File

@@ -671,11 +671,15 @@ components:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or 'amount' is
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount' is
required.
tier_behavior:
enum:
@@ -801,6 +805,27 @@ components:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -999,6 +1024,10 @@ components:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
@@ -2100,11 +2129,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -2449,12 +2481,16 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount'
is required.
tier_behavior:
enum:
- graduated
@@ -2581,6 +2617,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -2906,12 +2963,16 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount'
is required.
tier_behavior:
enum:
- graduated
@@ -3038,6 +3099,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -3342,11 +3424,15 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or
'amount' is required.
tier_behavior:
enum:
@@ -3476,6 +3562,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -3706,11 +3813,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -4041,12 +4151,16 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include
the included amount. Either 'tiers' or
'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the
included amount. Either 'tiers' or 'amount'
is required.
tier_behavior:
enum:
- graduated
@@ -4173,6 +4287,27 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription,
upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -5083,7 +5218,7 @@ paths:
- *a1
/v1/billing.attach:
post:
operationId: billingAttach
operationId: attach
description: >-
Attaches a plan to a customer. Handles new subscriptions, upgrades and
downgrades.
@@ -5306,11 +5441,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -5577,7 +5715,7 @@ paths:
- *a1
/v1/billing.multi_attach:
post:
operationId: billingMultiAttach
operationId: multiAttach
description: |-
Attaches multiple plans to a customer in a single request. Creates a single Stripe subscription with all plans consolidated.
@@ -5723,11 +5861,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -6235,11 +6376,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -6647,11 +6791,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -7170,11 +7317,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -7603,11 +7753,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -8042,11 +8195,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount.
Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -8662,6 +8818,12 @@ paths:
amount:
type: number
description: The price of the product item for this tier.
flat_amount:
anyOf:
- type: number
- type: "null"
description: A flat fee charged for this tier, in addition to the per-unit
amount.
required:
- to
- amount

View File

@@ -15,7 +15,7 @@ const SCHEMA_SOURCES: SchemaSource[] = [
sdkFile: "get-or-create-customer-op.ts",
outputFile: "getOrCreateCustomerSchemas.ts",
},
{ sdkFile: "billing-attach-op.ts", outputFile: "billingAttachSchemas.ts" },
{ sdkFile: "attach-op.ts", outputFile: "attachSchemas.ts" },
{
sdkFile: "open-customer-portal-op.ts",
outputFile: "openCustomerPortalSchemas.ts",

View File

@@ -25,7 +25,7 @@ export const billingAttachContract = oc
.route({
method: "POST",
path: "/v1/billing.attach",
operationId: "billingAttach",
operationId: "attach",
tags: ["billing"],
description: billingAttachJsDoc,
spec: (spec) => ({
@@ -231,7 +231,7 @@ export const billingMultiAttachContract = oc
.route({
method: "POST",
path: "/v1/billing.multi_attach",
operationId: "billingMultiAttach",
operationId: "multiAttach",
tags: ["billing"],
description: billingMultiAttachJsDoc,
spec: (spec) => ({
@@ -247,7 +247,10 @@ export const billingMultiAttachContract = oc
customer_id: "cus_123",
plans: [
{ plan_id: "pro_plan" },
{ plan_id: "addon_seats", feature_quantities: [{ feature_id: "seats", quantity: 5 }] },
{
plan_id: "addon_seats",
feature_quantities: [{ feature_id: "seats", quantity: 5 }],
},
],
},
],
@@ -291,7 +294,10 @@ export const billingPreviewMultiAttachContract = oc
customer_id: "cus_123",
plans: [
{ plan_id: "pro_plan" },
{ plan_id: "addon_seats", feature_quantities: [{ feature_id: "seats", quantity: 5 }] },
{
plan_id: "addon_seats",
feature_quantities: [{ feature_id: "seats", quantity: 5 }],
},
],
},
],

View File

@@ -123,6 +123,42 @@ actions:
console.log(result);
}
run();
- target: $["paths"]["/v1/billing.multi_attach"]["post"]
update:
x-codeSamples:
- lang: typescript
label: Typescript (SDK)
source: |-
import { Autumn } from "@useautumn/sdk";
const autumn = new Autumn({
xApiVersion: "2.1",
secretKey: process.env["AUTUMN_SECRET_KEY"] ?? "",
});
async function run() {
const result = await autumn.billing.multiAttach({
customerId: "cus_123",
plans: [
{
planId: "pro_plan",
},
{
planId: "addon_seats",
featureQuantities: [
{
featureId: "seats",
quantity: 5,
},
],
},
],
});
console.log(result);
}
run();
- target: $["paths"]["/v1/billing.open_customer_portal"]["post"]
update:
@@ -169,6 +205,42 @@ actions:
console.log(result);
}
run();
- target: $["paths"]["/v1/billing.preview_multi_attach"]["post"]
update:
x-codeSamples:
- lang: typescript
label: Typescript (SDK)
source: |-
import { Autumn } from "@useautumn/sdk";
const autumn = new Autumn({
xApiVersion: "2.1",
secretKey: process.env["AUTUMN_SECRET_KEY"] ?? "",
});
async function run() {
const result = await autumn.billing.previewMultiAttach({
customerId: "cus_123",
plans: [
{
planId: "pro_plan",
},
{
planId: "addon_seats",
featureQuantities: [
{
featureId: "seats",
quantity: 5,
},
],
},
],
});
console.log(result);
}
run();
- target: $["paths"]["/v1/billing.preview_update"]["post"]
update:

File diff suppressed because it is too large Load Diff

View File

@@ -18,8 +18,8 @@ generation:
sharedErrorComponentsApr2025: true
sharedNestedComponentsJan2026: true
auth:
oAuth2ClientCredentialsEnabled: true
oAuth2PasswordEnabled: true
oAuth2ClientCredentialsEnabled: false
oAuth2PasswordEnabled: false
hoistGlobalSecurity: true
inferSSEOverload: true
sdkHooksConfigAccess: true

View File

@@ -653,10 +653,14 @@ components:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
tier_behavior:
enum:
- graduated
@@ -768,6 +772,26 @@ components:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -954,6 +978,10 @@ components:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
@@ -2023,10 +2051,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -2349,10 +2381,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
tier_behavior:
enum:
- graduated
@@ -2464,6 +2500,26 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -2773,10 +2829,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
tier_behavior:
enum:
- graduated
@@ -2888,6 +2948,26 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -3175,10 +3255,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
tier_behavior:
enum:
- graduated
@@ -3290,6 +3374,26 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -3514,10 +3618,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -3826,10 +3934,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
description: Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
tier_behavior:
enum:
- graduated
@@ -3941,6 +4053,26 @@ paths:
- type: string
- type: "null"
description: If this is a variant, the ID of the base plan it was created from.
customer_eligibility:
type: object
properties:
trial_available:
type: boolean
description: Whether a free trial is available for this customer.
scenario:
enum:
- scheduled
- active
- new
- renew
- upgrade
- downgrade
- cancel
- expired
- past_due
description: The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
required:
- scenario
required:
- id
- name
@@ -4766,7 +4898,7 @@ paths:
- *a1
/v1/billing.attach:
post:
operationId: billingAttach
operationId: attach
description: >-
Attaches a plan to a customer. Handles new subscriptions, upgrades and downgrades.
@@ -4957,10 +5089,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -5198,7 +5334,7 @@ paths:
- *a1
/v1/billing.multi_attach:
post:
operationId: billingMultiAttach
operationId: multiAttach
description: |-
Attaches multiple plans to a customer in a single request. Creates a single Stripe subscription with all plans consolidated.
@@ -5339,10 +5475,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -5796,10 +5936,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -6176,10 +6320,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -6649,10 +6797,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -7033,10 +7185,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -7437,10 +7593,14 @@ paths:
- const: inf
amount:
type: number
flat_amount:
anyOf:
- type: number
- type: "null"
required:
- to
- amount
description: Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
description: Tiered pricing. Either 'amount' or 'tiers' is required.
tier_behavior:
enum:
- graduated
@@ -7997,6 +8157,11 @@ paths:
amount:
type: number
description: The price of the product item for this tier.
flat_amount:
anyOf:
- type: number
- type: "null"
description: A flat fee charged for this tier, in addition to the per-unit amount.
required:
- to
- amount

View File

@@ -9,8 +9,8 @@ sources:
- 2.1.0
Autumn API Stripped:
sourceNamespace: autumn-api-stripped
sourceRevisionDigest: sha256:13c128ac6c8d14e4b8798a7e20e5bfddbe23bc9d81acd823e7ce1bbd8094df51
sourceBlobDigest: sha256:d0a67193a48e8da4c35f51c068715773f84b918076c1627eb9286794513f7f1b
sourceRevisionDigest: sha256:0e77060348da59b47343432bbbea51335e0a24d5b9d2f8421ded72c6b88f8219
sourceBlobDigest: sha256:84fcb60481c185f7ad9256f109b8062d87ced544d9ac4af820463e9df9fd8849
tags:
- latest
- 2.1.0
@@ -25,10 +25,10 @@ targets:
autumn-python:
source: Autumn API Stripped
sourceNamespace: autumn-api-stripped
sourceRevisionDigest: sha256:13c128ac6c8d14e4b8798a7e20e5bfddbe23bc9d81acd823e7ce1bbd8094df51
sourceBlobDigest: sha256:d0a67193a48e8da4c35f51c068715773f84b918076c1627eb9286794513f7f1b
sourceRevisionDigest: sha256:0e77060348da59b47343432bbbea51335e0a24d5b9d2f8421ded72c6b88f8219
sourceBlobDigest: sha256:84fcb60481c185f7ad9256f109b8062d87ced544d9ac4af820463e9df9fd8849
codeSamplesNamespace: autumn-api-python-code-samples
codeSamplesRevisionDigest: sha256:ce4215f239e65976dbfffcd7e5d76f506dc0ba33a3046a99f846502ff192fe71
codeSamplesRevisionDigest: sha256:b00ce89ddc8577cb090cc62b69897399a86e097c20daa91df471c31e7aa09230
workflow:
workflowVersion: 1.0.0
speakeasyVersion: pinned

View File

@@ -246,6 +246,41 @@ const response = await client.billing.attach({ customerId: "cus_123", planId: "p
@param successUrl - URL to redirect to after successful checkout. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@param planSchedule - When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@returns A billing response with customer ID, invoice details, and payment URL (if checkout required).
* [multiAttach](docs/sdks/billing/README.md#multiattach) - Attaches multiple plans to a customer in a single request. Creates a single Stripe subscription with all plans consolidated.
Use this endpoint when you need to subscribe a customer to multiple plans at once, such as a base plan plus add-ons, or to create a bundle of products.
@example
```typescript
// Attach multiple plans to a customer
const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_seats","featureQuantities":[{"featureId":"seats","quantity":5}]}] });
```
@example
```typescript
// Attach with free trial applied to all plans
const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_storage"}], freeTrial: {"durationLength":14,"durationType":"day"} });
```
@example
```typescript
// Attach with custom pricing on one plan
const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan","customize":{"price":{"amount":4900,"interval":"month"}}},{"planId":"addon_support"}] });
```
@param customerId - The ID of the customer to attach the plans to.
@param entityId - The ID of the entity to attach the plans to. (optional)
@param plans - The list of plans to attach to the customer.
@param freeTrial - Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial. (optional)
@param invoiceMode - Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. (optional)
@param discounts - List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code. (optional)
@param successUrl - URL to redirect to after successful checkout. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@param redirectMode - Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@returns A billing response with customer ID, invoice details, and payment URL (if checkout required).
* [previewAttach](docs/sdks/billing/README.md#previewattach) - Previews the billing changes that would occur when attaching a plan, without actually making any changes.
@@ -270,8 +305,31 @@ const response = await client.billing.previewAttach({ customerId: "cus_123", pla
@param successUrl - URL to redirect to after successful checkout. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@param planSchedule - When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@returns A preview response with line items, totals, and effective dates for the proposed changes.
* [previewMultiAttach](docs/sdks/billing/README.md#previewmultiattach) - Previews the billing changes that would occur when attaching multiple plans, without actually making any changes.
Use this endpoint to show customers what they will be charged before confirming a multi-plan subscription.
@example
```typescript
// Preview attaching multiple plans
const response = await client.billing.previewMultiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_seats","featureQuantities":[{"featureId":"seats","quantity":5}]}] });
```
@param customerId - The ID of the customer to attach the plans to.
@param entityId - The ID of the entity to attach the plans to. (optional)
@param plans - The list of plans to attach to the customer.
@param freeTrial - Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial. (optional)
@param invoiceMode - Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. (optional)
@param discounts - List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code. (optional)
@param successUrl - URL to redirect to after successful checkout. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@param redirectMode - Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@returns A preview response with line items, totals, and effective dates for the proposed multi-plan attachment.
* [update](docs/sdks/billing/README.md#update) - Updates an existing subscription. Use to modify feature quantities, cancel, or change plan configuration.
Use this endpoint to update prepaid quantities, cancel a subscription (immediately or at end of cycle), or modify subscription settings.
@@ -575,6 +633,41 @@ const response = await client.billing.attach({ customerId: "cus_123", planId: "p
@param successUrl - URL to redirect to after successful checkout. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@param planSchedule - When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@returns A billing response with customer ID, invoice details, and payment URL (if checkout required).
- [`billingMultiAttach`](docs/sdks/billing/README.md#multiattach) - Attaches multiple plans to a customer in a single request. Creates a single Stripe subscription with all plans consolidated.
Use this endpoint when you need to subscribe a customer to multiple plans at once, such as a base plan plus add-ons, or to create a bundle of products.
@example
```typescript
// Attach multiple plans to a customer
const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_seats","featureQuantities":[{"featureId":"seats","quantity":5}]}] });
```
@example
```typescript
// Attach with free trial applied to all plans
const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_storage"}], freeTrial: {"durationLength":14,"durationType":"day"} });
```
@example
```typescript
// Attach with custom pricing on one plan
const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan","customize":{"price":{"amount":4900,"interval":"month"}}},{"planId":"addon_support"}] });
```
@param customerId - The ID of the customer to attach the plans to.
@param entityId - The ID of the entity to attach the plans to. (optional)
@param plans - The list of plans to attach to the customer.
@param freeTrial - Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial. (optional)
@param invoiceMode - Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. (optional)
@param discounts - List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code. (optional)
@param successUrl - URL to redirect to after successful checkout. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@param redirectMode - Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@returns A billing response with customer ID, invoice details, and payment URL (if checkout required).
- [`billingOpenCustomerPortal`](docs/sdks/billing/README.md#opencustomerportal) - Create a billing portal session for a customer to manage their subscription.
@@ -600,8 +693,31 @@ const response = await client.billing.previewAttach({ customerId: "cus_123", pla
@param successUrl - URL to redirect to after successful checkout. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@param planSchedule - When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@returns A preview response with line items, totals, and effective dates for the proposed changes.
- [`billingPreviewMultiAttach`](docs/sdks/billing/README.md#previewmultiattach) - Previews the billing changes that would occur when attaching multiple plans, without actually making any changes.
Use this endpoint to show customers what they will be charged before confirming a multi-plan subscription.
@example
```typescript
// Preview attaching multiple plans
const response = await client.billing.previewMultiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_seats","featureQuantities":[{"featureId":"seats","quantity":5}]}] });
```
@param customerId - The ID of the customer to attach the plans to.
@param entityId - The ID of the entity to attach the plans to. (optional)
@param plans - The list of plans to attach to the customer.
@param freeTrial - Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial. (optional)
@param invoiceMode - Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. (optional)
@param discounts - List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code. (optional)
@param successUrl - URL to redirect to after successful checkout. (optional)
@param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
@param redirectMode - Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects. (optional)
@param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
@returns A preview response with line items, totals, and effective dates for the proposed multi-plan attachment.
- [`billingPreviewUpdate`](docs/sdks/billing/README.md#previewupdate) - Previews the billing changes that would occur when updating a subscription, without actually making any changes.
Use this endpoint to show customers prorated charges or refunds before confirming subscription modifications.

View File

@@ -60,6 +60,7 @@ import { Result } from "../types/fp.js";
* @param successUrl - URL to redirect to after successful checkout. (optional)
* @param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
* @param planSchedule - When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled. (optional)
* @param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
*
* @returns A billing response with customer ID, invoice details, and payment URL (if checkout required).
*/
@@ -69,7 +70,7 @@ export function billingAttach(
options?: RequestOptions,
): APIPromise<
Result<
models.BillingAttachResponse,
models.AttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
@@ -94,7 +95,7 @@ async function $do(
): Promise<
[
Result<
models.BillingAttachResponse,
models.AttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
@@ -137,7 +138,7 @@ async function $do(
const context = {
options: client._options,
baseURL: options?.serverURL ?? client._baseURL ?? "",
operationID: "billingAttach",
operationID: "attach",
oAuth2Scopes: null,
resolvedSecurity: requestSecurity,
@@ -176,7 +177,7 @@ async function $do(
const response = doResult.value;
const [result] = await M.match<
models.BillingAttachResponse,
models.AttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
@@ -186,7 +187,7 @@ async function $do(
| UnexpectedClientError
| SDKValidationError
>(
M.json(200, models.BillingAttachResponse$inboundSchema),
M.json(200, models.AttachResponse$inboundSchema),
M.fail("4XX"),
M.fail("5XX"),
)(response, req);

View File

@@ -0,0 +1,196 @@
/*
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
*/
import * as z from "zod/v4-mini";
import { AutumnCore } from "../core.js";
import { encodeJSON, encodeSimple } from "../lib/encodings.js";
import * as M from "../lib/matchers.js";
import { compactMap } from "../lib/primitives.js";
import { safeParse } from "../lib/schemas.js";
import { RequestOptions } from "../lib/sdks.js";
import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
import { pathToFunc } from "../lib/url.js";
import { AutumnError } from "../models/autumn-error.js";
import {
ConnectionError,
InvalidRequestError,
RequestAbortedError,
RequestTimeoutError,
UnexpectedClientError,
} from "../models/http-client-errors.js";
import * as models from "../models/index.js";
import { ResponseValidationError } from "../models/response-validation-error.js";
import { SDKValidationError } from "../models/sdk-validation-error.js";
import { APICall, APIPromise } from "../types/async.js";
import { Result } from "../types/fp.js";
/**
* Attaches multiple plans to a customer in a single request. Creates a single Stripe subscription with all plans consolidated.
*
* Use this endpoint when you need to subscribe a customer to multiple plans at once, such as a base plan plus add-ons, or to create a bundle of products.
*
* @example
* ```typescript
* // Attach multiple plans to a customer
* const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_seats","featureQuantities":[{"featureId":"seats","quantity":5}]}] });
* ```
*
* @example
* ```typescript
* // Attach with free trial applied to all plans
* const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_storage"}], freeTrial: {"durationLength":14,"durationType":"day"} });
* ```
*
* @example
* ```typescript
* // Attach with custom pricing on one plan
* const response = await client.billing.multiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan","customize":{"price":{"amount":4900,"interval":"month"}}},{"planId":"addon_support"}] });
* ```
*
* @param customerId - The ID of the customer to attach the plans to.
* @param entityId - The ID of the entity to attach the plans to. (optional)
* @param plans - The list of plans to attach to the customer.
* @param freeTrial - Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial. (optional)
* @param invoiceMode - Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. (optional)
* @param discounts - List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code. (optional)
* @param successUrl - URL to redirect to after successful checkout. (optional)
* @param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
* @param redirectMode - Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects. (optional)
* @param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
*
* @returns A billing response with customer ID, invoice details, and payment URL (if checkout required).
*/
export function billingMultiAttach(
client: AutumnCore,
request: models.MultiAttachParams,
options?: RequestOptions,
): APIPromise<
Result<
models.MultiAttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
| RequestAbortedError
| RequestTimeoutError
| InvalidRequestError
| UnexpectedClientError
| SDKValidationError
>
> {
return new APIPromise($do(
client,
request,
options,
));
}
async function $do(
client: AutumnCore,
request: models.MultiAttachParams,
options?: RequestOptions,
): Promise<
[
Result<
models.MultiAttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
| RequestAbortedError
| RequestTimeoutError
| InvalidRequestError
| UnexpectedClientError
| SDKValidationError
>,
APICall,
]
> {
const parsed = safeParse(
request,
(value) => z.parse(models.MultiAttachParams$outboundSchema, value),
"Input validation failed",
);
if (!parsed.ok) {
return [parsed, { status: "invalid" }];
}
const payload = parsed.value;
const body = encodeJSON("body", payload, { explode: true });
const path = pathToFunc("/v1/billing.multi_attach")();
const headers = new Headers(compactMap({
"Content-Type": "application/json",
Accept: "application/json",
"x-api-version": encodeSimple(
"x-api-version",
client._options.xApiVersion,
{ explode: false, charEncoding: "none" },
),
}));
const secConfig = await extractSecurity(client._options.secretKey);
const securityInput = secConfig == null ? {} : { secretKey: secConfig };
const requestSecurity = resolveGlobalSecurity(securityInput);
const context = {
options: client._options,
baseURL: options?.serverURL ?? client._baseURL ?? "",
operationID: "multiAttach",
oAuth2Scopes: null,
resolvedSecurity: requestSecurity,
securitySource: client._options.secretKey,
retryConfig: options?.retries
|| client._options.retryConfig
|| { strategy: "none" },
retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"],
};
const requestRes = client._createRequest(context, {
security: requestSecurity,
method: "POST",
baseURL: options?.serverURL,
path: path,
headers: headers,
body: body,
userAgent: client._options.userAgent,
timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1,
}, options);
if (!requestRes.ok) {
return [requestRes, { status: "invalid" }];
}
const req = requestRes.value;
const doResult = await client._do(req, {
context,
errorCodes: ["4XX", "5XX"],
retryConfig: context.retryConfig,
retryCodes: context.retryCodes,
});
if (!doResult.ok) {
return [doResult, { status: "request-error", request: req }];
}
const response = doResult.value;
const [result] = await M.match<
models.MultiAttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
| RequestAbortedError
| RequestTimeoutError
| InvalidRequestError
| UnexpectedClientError
| SDKValidationError
>(
M.json(200, models.MultiAttachResponse$inboundSchema),
M.fail("4XX"),
M.fail("5XX"),
)(response, req);
if (!result.ok) {
return [result, { status: "complete", request: req, response }];
}
return [result, { status: "complete", request: req, response }];
}

View File

@@ -48,6 +48,7 @@ import { Result } from "../types/fp.js";
* @param successUrl - URL to redirect to after successful checkout. (optional)
* @param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
* @param planSchedule - When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled. (optional)
* @param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
*
* @returns A preview response with line items, totals, and effective dates for the proposed changes.
*/

View File

@@ -0,0 +1,184 @@
/*
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
*/
import * as z from "zod/v4-mini";
import { AutumnCore } from "../core.js";
import { encodeJSON, encodeSimple } from "../lib/encodings.js";
import * as M from "../lib/matchers.js";
import { compactMap } from "../lib/primitives.js";
import { safeParse } from "../lib/schemas.js";
import { RequestOptions } from "../lib/sdks.js";
import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
import { pathToFunc } from "../lib/url.js";
import { AutumnError } from "../models/autumn-error.js";
import {
ConnectionError,
InvalidRequestError,
RequestAbortedError,
RequestTimeoutError,
UnexpectedClientError,
} from "../models/http-client-errors.js";
import * as models from "../models/index.js";
import { ResponseValidationError } from "../models/response-validation-error.js";
import { SDKValidationError } from "../models/sdk-validation-error.js";
import { APICall, APIPromise } from "../types/async.js";
import { Result } from "../types/fp.js";
/**
* Previews the billing changes that would occur when attaching multiple plans, without actually making any changes.
*
* Use this endpoint to show customers what they will be charged before confirming a multi-plan subscription.
*
* @example
* ```typescript
* // Preview attaching multiple plans
* const response = await client.billing.previewMultiAttach({ customerId: "cus_123", plans: [{"planId":"pro_plan"},{"planId":"addon_seats","featureQuantities":[{"featureId":"seats","quantity":5}]}] });
* ```
*
* @param customerId - The ID of the customer to attach the plans to.
* @param entityId - The ID of the entity to attach the plans to. (optional)
* @param plans - The list of plans to attach to the customer.
* @param freeTrial - Free trial configuration applied to all plans. Pass an object to set a custom trial, or null to remove any trial. (optional)
* @param invoiceMode - Invoice mode creates a draft or open invoice and sends it to the customer, instead of charging their card immediately. (optional)
* @param discounts - List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code. (optional)
* @param successUrl - URL to redirect to after successful checkout. (optional)
* @param checkoutSessionParams - Additional parameters to pass into the creation of the Stripe checkout session. (optional)
* @param redirectMode - Controls when to return a checkout URL. 'always' returns a URL even if payment succeeds, 'if_required' only when payment action is needed, 'never' disables redirects. (optional)
* @param newBillingSubscription - Only applicable when the customer has an existing Stripe subscription. If true, creates a new separate subscription instead of merging into the existing one. (optional)
*
* @returns A preview response with line items, totals, and effective dates for the proposed multi-plan attachment.
*/
export function billingPreviewMultiAttach(
client: AutumnCore,
request: models.PreviewMultiAttachParams,
options?: RequestOptions,
): APIPromise<
Result<
models.PreviewMultiAttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
| RequestAbortedError
| RequestTimeoutError
| InvalidRequestError
| UnexpectedClientError
| SDKValidationError
>
> {
return new APIPromise($do(
client,
request,
options,
));
}
async function $do(
client: AutumnCore,
request: models.PreviewMultiAttachParams,
options?: RequestOptions,
): Promise<
[
Result<
models.PreviewMultiAttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
| RequestAbortedError
| RequestTimeoutError
| InvalidRequestError
| UnexpectedClientError
| SDKValidationError
>,
APICall,
]
> {
const parsed = safeParse(
request,
(value) => z.parse(models.PreviewMultiAttachParams$outboundSchema, value),
"Input validation failed",
);
if (!parsed.ok) {
return [parsed, { status: "invalid" }];
}
const payload = parsed.value;
const body = encodeJSON("body", payload, { explode: true });
const path = pathToFunc("/v1/billing.preview_multi_attach")();
const headers = new Headers(compactMap({
"Content-Type": "application/json",
Accept: "application/json",
"x-api-version": encodeSimple(
"x-api-version",
client._options.xApiVersion,
{ explode: false, charEncoding: "none" },
),
}));
const secConfig = await extractSecurity(client._options.secretKey);
const securityInput = secConfig == null ? {} : { secretKey: secConfig };
const requestSecurity = resolveGlobalSecurity(securityInput);
const context = {
options: client._options,
baseURL: options?.serverURL ?? client._baseURL ?? "",
operationID: "previewMultiAttach",
oAuth2Scopes: null,
resolvedSecurity: requestSecurity,
securitySource: client._options.secretKey,
retryConfig: options?.retries
|| client._options.retryConfig
|| { strategy: "none" },
retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"],
};
const requestRes = client._createRequest(context, {
security: requestSecurity,
method: "POST",
baseURL: options?.serverURL,
path: path,
headers: headers,
body: body,
userAgent: client._options.userAgent,
timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1,
}, options);
if (!requestRes.ok) {
return [requestRes, { status: "invalid" }];
}
const req = requestRes.value;
const doResult = await client._do(req, {
context,
errorCodes: ["4XX", "5XX"],
retryConfig: context.retryConfig,
retryCodes: context.retryCodes,
});
if (!doResult.ok) {
return [doResult, { status: "request-error", request: req }];
}
const response = doResult.value;
const [result] = await M.match<
models.PreviewMultiAttachResponse,
| AutumnError
| ResponseValidationError
| ConnectionError
| RequestAbortedError
| RequestTimeoutError
| InvalidRequestError
| UnexpectedClientError
| SDKValidationError
>(
M.json(200, models.PreviewMultiAttachResponse$inboundSchema),
M.fail("4XX"),
M.fail("5XX"),
)(response, req);
if (!result.ok) {
return [result, { status: "complete", request: req, response }];
}
return [result, { status: "complete", request: req, response }];
}

View File

@@ -18,8 +18,6 @@ import {
SDKInitHook,
} from "./types.js";
import { initHooks } from "./registration.js";
export class SDKHooks implements Hooks {
sdkInitHooks: SDKInitHook[] = [];
beforeCreateRequestHooks: BeforeCreateRequestHook[] = [];
@@ -47,7 +45,6 @@ export class SDKHooks implements Hooks {
this.registerAfterErrorHook(hook);
}
}
initHooks(this);
}
registerSDKInitHook(hook: SDKInitHook) {

View File

@@ -126,8 +126,21 @@ export type BalanceTo = number | string;
export type BalanceTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
/**
* How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
*/
export const BalanceTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
/**
* How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
*/
export type BalanceTierBehavior = OpenEnum<typeof BalanceTierBehavior>;
/**
* Whether usage is prepaid or billed pay-per-use.
*/
@@ -149,6 +162,10 @@ export type BalancePrice = {
* Tiered pricing configuration if applicable.
*/
tiers?: Array<BalanceTier> | undefined;
/**
* How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier).
*/
tierBehavior?: BalanceTierBehavior | undefined;
/**
* The number of units per billing increment (eg. $9 / 250 units).
*/
@@ -411,10 +428,18 @@ export function balanceToFromJSON(
/** @internal */
export const BalanceTier$inboundSchema: z.ZodMiniType<BalanceTier, unknown> = z
.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
});
.pipe(
z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
flat_amount: z.optional(z.nullable(types.number())),
}),
z.transform((v) => {
return remap$(v, {
"flat_amount": "flatAmount",
});
}),
);
export function balanceTierFromJSON(
jsonString: string,
@@ -426,6 +451,12 @@ export function balanceTierFromJSON(
);
}
/** @internal */
export const BalanceTierBehavior$inboundSchema: z.ZodMiniType<
BalanceTierBehavior,
unknown
> = openEnums.inboundSchema(BalanceTierBehavior);
/** @internal */
export const BalanceBillingMethod$inboundSchema: z.ZodMiniType<
BalanceBillingMethod,
@@ -438,12 +469,14 @@ export const BalancePrice$inboundSchema: z.ZodMiniType<BalancePrice, unknown> =
z.object({
amount: types.optional(types.number()),
tiers: types.optional(z.array(z.lazy(() => BalanceTier$inboundSchema))),
tier_behavior: types.optional(BalanceTierBehavior$inboundSchema),
billing_units: types.number(),
billing_method: BalanceBillingMethod$inboundSchema,
max_purchase: types.nullable(types.number()),
}),
z.transform((v) => {
return remap$(v, {
"tier_behavior": "tierBehavior",
"billing_units": "billingUnits",
"billing_method": "billingMethod",
"max_purchase": "maxPurchase",

View File

@@ -110,8 +110,17 @@ export type BillingUpdateTo = number | string;
export type BillingUpdateTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const BillingUpdateTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type BillingUpdateTierBehavior = ClosedEnum<
typeof BillingUpdateTierBehavior
>;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -153,9 +162,10 @@ export type BillingUpdatePrice = {
*/
amount?: number | undefined;
/**
* Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
* Tiered pricing. Either 'amount' or 'tiers' is required.
*/
tiers?: Array<BillingUpdateTier> | undefined;
tierBehavior?: BillingUpdateTierBehavior | undefined;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -632,16 +642,25 @@ export function billingUpdateToToJSON(
export type BillingUpdateTier$Outbound = {
to: number | string;
amount: number;
flat_amount?: number | null | undefined;
};
/** @internal */
export const BillingUpdateTier$outboundSchema: z.ZodMiniType<
BillingUpdateTier$Outbound,
BillingUpdateTier
> = z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
});
> = z.pipe(
z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.optional(z.nullable(z.number())),
}),
z.transform((v) => {
return remap$(v, {
flatAmount: "flat_amount",
});
}),
);
export function billingUpdateTierToJSON(
billingUpdateTier: BillingUpdateTier,
@@ -651,6 +670,11 @@ export function billingUpdateTierToJSON(
);
}
/** @internal */
export const BillingUpdateTierBehavior$outboundSchema: z.ZodMiniEnum<
typeof BillingUpdateTierBehavior
> = z.enum(BillingUpdateTierBehavior);
/** @internal */
export const BillingUpdateItemPriceInterval$outboundSchema: z.ZodMiniEnum<
typeof BillingUpdateItemPriceInterval
@@ -665,6 +689,7 @@ export const BillingUpdateBillingMethod$outboundSchema: z.ZodMiniEnum<
export type BillingUpdatePrice$Outbound = {
amount?: number | undefined;
tiers?: Array<BillingUpdateTier$Outbound> | undefined;
tier_behavior?: string | undefined;
interval: string;
interval_count: number;
billing_units: number;
@@ -680,6 +705,7 @@ export const BillingUpdatePrice$outboundSchema: z.ZodMiniType<
z.object({
amount: z.optional(z.number()),
tiers: z.optional(z.array(z.lazy(() => BillingUpdateTier$outboundSchema))),
tierBehavior: z.optional(BillingUpdateTierBehavior$outboundSchema),
interval: BillingUpdateItemPriceInterval$outboundSchema,
intervalCount: z._default(z.number(), 1),
billingUnits: z._default(z.number(), 1),
@@ -688,6 +714,7 @@ export const BillingUpdatePrice$outboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
tierBehavior: "tier_behavior",
intervalCount: "interval_count",
billingUnits: "billing_units",
billingMethod: "billing_method",

View File

@@ -51,14 +51,14 @@ export type CheckParams = {
/**
* The reason access was denied. 'usage_limit' means the customer exceeded their balance, 'feature_flag' means the feature is not included in their plan.
*/
export const Scenario = {
export const CheckScenario = {
UsageLimit: "usage_limit",
FeatureFlag: "feature_flag",
} as const;
/**
* The reason access was denied. 'usage_limit' means the customer exceeded their balance, 'feature_flag' means the feature is not included in their plan.
*/
export type Scenario = OpenEnum<typeof Scenario>;
export type CheckScenario = OpenEnum<typeof CheckScenario>;
/**
* The environment of the product
@@ -115,8 +115,18 @@ export type Tiers = {
* The price of the product item for this tier.
*/
amount: number;
/**
* A flat fee charged for this tier, in addition to the per-unit amount.
*/
flatAmount?: number | null | undefined;
};
export const CheckTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type CheckTierBehavior = OpenEnum<typeof CheckTierBehavior>;
export const UsageModel = {
Prepaid: "prepaid",
PayPerUse: "pay_per_use",
@@ -199,6 +209,10 @@ export type CheckItem = {
* Tiered pricing for the product item. Not applicable for fixed price items.
*/
tiers?: Array<Tiers> | null | undefined;
/**
* How tiers are applied: graduated (split across bands) or volume (flat rate for the matched tier). Defaults to graduated.
*/
tierBehavior?: CheckTierBehavior | null | undefined;
/**
* Whether the feature should be prepaid upfront or billed for how much they use end of billing period.
*/
@@ -374,7 +388,7 @@ export type Preview = {
/**
* The reason access was denied. 'usage_limit' means the customer exceeded their balance, 'feature_flag' means the feature is not included in their plan.
*/
scenario: Scenario;
scenario: CheckScenario;
/**
* A title suitable for displaying in a paywall or upgrade modal.
*/
@@ -469,8 +483,10 @@ export function checkParamsToJSON(checkParams: CheckParams): string {
}
/** @internal */
export const Scenario$inboundSchema: z.ZodMiniType<Scenario, unknown> =
openEnums.inboundSchema(Scenario);
export const CheckScenario$inboundSchema: z.ZodMiniType<
CheckScenario,
unknown
> = openEnums.inboundSchema(CheckScenario);
/** @internal */
export const CheckEnv$inboundSchema: z.ZodMiniType<CheckEnv, unknown> =
@@ -521,10 +537,18 @@ export function checkToFromJSON(
}
/** @internal */
export const Tiers$inboundSchema: z.ZodMiniType<Tiers, unknown> = z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
});
export const Tiers$inboundSchema: z.ZodMiniType<Tiers, unknown> = z.pipe(
z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
flat_amount: z.optional(z.nullable(types.number())),
}),
z.transform((v) => {
return remap$(v, {
"flat_amount": "flatAmount",
});
}),
);
export function tiersFromJSON(
jsonString: string,
@@ -536,6 +560,12 @@ export function tiersFromJSON(
);
}
/** @internal */
export const CheckTierBehavior$inboundSchema: z.ZodMiniType<
CheckTierBehavior,
unknown
> = openEnums.inboundSchema(CheckTierBehavior);
/** @internal */
export const UsageModel$inboundSchema: z.ZodMiniType<UsageModel, unknown> =
openEnums.inboundSchema(UsageModel);
@@ -642,6 +672,7 @@ export const CheckItem$inboundSchema: z.ZodMiniType<CheckItem, unknown> = z
interval_count: z.optional(z.nullable(types.number())),
price: z.optional(z.nullable(types.number())),
tiers: z.optional(z.nullable(z.array(z.lazy(() => Tiers$inboundSchema)))),
tier_behavior: z.optional(z.nullable(CheckTierBehavior$inboundSchema)),
usage_model: z.optional(z.nullable(UsageModel$inboundSchema)),
billing_units: z.optional(z.nullable(types.number())),
reset_usage_when_enabled: z.optional(z.nullable(types.boolean())),
@@ -657,6 +688,7 @@ export const CheckItem$inboundSchema: z.ZodMiniType<CheckItem, unknown> = z
"feature_type": "featureType",
"included_usage": "includedUsage",
"interval_count": "intervalCount",
"tier_behavior": "tierBehavior",
"usage_model": "usageModel",
"billing_units": "billingUnits",
"reset_usage_when_enabled": "resetUsageWhenEnabled",
@@ -793,7 +825,7 @@ export function productFromJSON(
/** @internal */
export const Preview$inboundSchema: z.ZodMiniType<Preview, unknown> = z.pipe(
z.object({
scenario: Scenario$inboundSchema,
scenario: CheckScenario$inboundSchema,
title: types.string(),
message: types.string(),
feature_id: types.string(),

View File

@@ -92,8 +92,17 @@ export type CreatePlanToRequest = number | string;
export type CreatePlanTierRequest = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const CreatePlanTierBehaviorRequest = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type CreatePlanTierBehaviorRequest = ClosedEnum<
typeof CreatePlanTierBehaviorRequest
>;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -135,9 +144,10 @@ export type CreatePlanItemPriceRequest = {
*/
amount?: number | undefined;
/**
* Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
* Tiered pricing. Either 'amount' or 'tiers' is required.
*/
tiers?: Array<CreatePlanTierRequest> | undefined;
tierBehavior?: CreatePlanTierBehaviorRequest | undefined;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -496,8 +506,17 @@ export type CreatePlanToResponse = number | string;
export type CreatePlanTierResponse = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const CreatePlanTierBehaviorResponse = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type CreatePlanTierBehaviorResponse = OpenEnum<
typeof CreatePlanTierBehaviorResponse
>;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -536,9 +555,10 @@ export type CreatePlanItemPriceResponse = {
*/
amount?: number | undefined;
/**
* Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
* Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
*/
tiers?: Array<CreatePlanTierResponse> | undefined;
tierBehavior?: CreatePlanTierBehaviorResponse | undefined;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -687,6 +707,36 @@ export const CreatePlanEnv = {
*/
export type CreatePlanEnv = OpenEnum<typeof CreatePlanEnv>;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export const CreatePlanScenario = {
Scheduled: "scheduled",
Active: "active",
New: "new",
Renew: "renew",
Upgrade: "upgrade",
Downgrade: "downgrade",
Cancel: "cancel",
Expired: "expired",
PastDue: "past_due",
} as const;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export type CreatePlanScenario = OpenEnum<typeof CreatePlanScenario>;
export type CreatePlanCustomerEligibility = {
/**
* Whether a free trial is available for this customer.
*/
trialAvailable?: boolean | undefined;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
scenario: CreatePlanScenario;
};
/**
* A plan defines a set of features, pricing, and entitlements that can be attached to customers.
*/
@@ -747,6 +797,7 @@ export type CreatePlanResponse = {
* If this is a variant, the ID of the base plan it was created from.
*/
baseVariantId: string | null;
customerEligibility?: CreatePlanCustomerEligibility | undefined;
};
/** @internal */
@@ -842,16 +893,25 @@ export function createPlanToRequestToJSON(
export type CreatePlanTierRequest$Outbound = {
to: number | string;
amount: number;
flat_amount?: number | null | undefined;
};
/** @internal */
export const CreatePlanTierRequest$outboundSchema: z.ZodMiniType<
CreatePlanTierRequest$Outbound,
CreatePlanTierRequest
> = z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
});
> = z.pipe(
z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.optional(z.nullable(z.number())),
}),
z.transform((v) => {
return remap$(v, {
flatAmount: "flat_amount",
});
}),
);
export function createPlanTierRequestToJSON(
createPlanTierRequest: CreatePlanTierRequest,
@@ -861,6 +921,11 @@ export function createPlanTierRequestToJSON(
);
}
/** @internal */
export const CreatePlanTierBehaviorRequest$outboundSchema: z.ZodMiniEnum<
typeof CreatePlanTierBehaviorRequest
> = z.enum(CreatePlanTierBehaviorRequest);
/** @internal */
export const CreatePlanItemPriceIntervalRequest$outboundSchema: z.ZodMiniEnum<
typeof CreatePlanItemPriceIntervalRequest
@@ -875,6 +940,7 @@ export const CreatePlanBillingMethodRequest$outboundSchema: z.ZodMiniEnum<
export type CreatePlanItemPriceRequest$Outbound = {
amount?: number | undefined;
tiers?: Array<CreatePlanTierRequest$Outbound> | undefined;
tier_behavior?: string | undefined;
interval: string;
interval_count: number;
billing_units: number;
@@ -892,6 +958,7 @@ export const CreatePlanItemPriceRequest$outboundSchema: z.ZodMiniType<
tiers: z.optional(
z.array(z.lazy(() => CreatePlanTierRequest$outboundSchema)),
),
tierBehavior: z.optional(CreatePlanTierBehaviorRequest$outboundSchema),
interval: CreatePlanItemPriceIntervalRequest$outboundSchema,
intervalCount: z._default(z.number(), 1),
billingUnits: z._default(z.number(), 1),
@@ -900,6 +967,7 @@ export const CreatePlanItemPriceRequest$outboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
tierBehavior: "tier_behavior",
intervalCount: "interval_count",
billingUnits: "billing_units",
billingMethod: "billing_method",
@@ -1325,10 +1393,18 @@ export function createPlanToResponseFromJSON(
export const CreatePlanTierResponse$inboundSchema: z.ZodMiniType<
CreatePlanTierResponse,
unknown
> = z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
});
> = z.pipe(
z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
flat_amount: z.optional(z.nullable(types.number())),
}),
z.transform((v) => {
return remap$(v, {
"flat_amount": "flatAmount",
});
}),
);
export function createPlanTierResponseFromJSON(
jsonString: string,
@@ -1340,6 +1416,12 @@ export function createPlanTierResponseFromJSON(
);
}
/** @internal */
export const CreatePlanTierBehaviorResponse$inboundSchema: z.ZodMiniType<
CreatePlanTierBehaviorResponse,
unknown
> = openEnums.inboundSchema(CreatePlanTierBehaviorResponse);
/** @internal */
export const CreatePlanPriceItemIntervalResponse$inboundSchema: z.ZodMiniType<
CreatePlanPriceItemIntervalResponse,
@@ -1362,6 +1444,7 @@ export const CreatePlanItemPriceResponse$inboundSchema: z.ZodMiniType<
tiers: types.optional(
z.array(z.lazy(() => CreatePlanTierResponse$inboundSchema)),
),
tier_behavior: types.optional(CreatePlanTierBehaviorResponse$inboundSchema),
interval: CreatePlanPriceItemIntervalResponse$inboundSchema,
interval_count: types.optional(types.number()),
billing_units: types.number(),
@@ -1370,6 +1453,7 @@ export const CreatePlanItemPriceResponse$inboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
"tier_behavior": "tierBehavior",
"interval_count": "intervalCount",
"billing_units": "billingUnits",
"billing_method": "billingMethod",
@@ -1526,6 +1610,38 @@ export const CreatePlanEnv$inboundSchema: z.ZodMiniType<
unknown
> = openEnums.inboundSchema(CreatePlanEnv);
/** @internal */
export const CreatePlanScenario$inboundSchema: z.ZodMiniType<
CreatePlanScenario,
unknown
> = openEnums.inboundSchema(CreatePlanScenario);
/** @internal */
export const CreatePlanCustomerEligibility$inboundSchema: z.ZodMiniType<
CreatePlanCustomerEligibility,
unknown
> = z.pipe(
z.object({
trial_available: types.optional(types.boolean()),
scenario: CreatePlanScenario$inboundSchema,
}),
z.transform((v) => {
return remap$(v, {
"trial_available": "trialAvailable",
});
}),
);
export function createPlanCustomerEligibilityFromJSON(
jsonString: string,
): SafeParseResult<CreatePlanCustomerEligibility, SDKValidationError> {
return safeParse(
jsonString,
(x) => CreatePlanCustomerEligibility$inboundSchema.parse(JSON.parse(x)),
`Failed to parse 'CreatePlanCustomerEligibility' from JSON`,
);
}
/** @internal */
export const CreatePlanResponse$inboundSchema: z.ZodMiniType<
CreatePlanResponse,
@@ -1548,6 +1664,9 @@ export const CreatePlanResponse$inboundSchema: z.ZodMiniType<
env: CreatePlanEnv$inboundSchema,
archived: types.boolean(),
base_variant_id: types.nullable(types.string()),
customer_eligibility: types.optional(
z.lazy(() => CreatePlanCustomerEligibility$inboundSchema),
),
}),
z.transform((v) => {
return remap$(v, {
@@ -1556,6 +1675,7 @@ export const CreatePlanResponse$inboundSchema: z.ZodMiniType<
"free_trial": "freeTrial",
"created_at": "createdAt",
"base_variant_id": "baseVariantId",
"customer_eligibility": "customerEligibility",
});
}),
);

View File

@@ -178,8 +178,15 @@ export type GetPlanTo = number | string;
export type GetPlanTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const GetPlanTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type GetPlanTierBehavior = OpenEnum<typeof GetPlanTierBehavior>;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -216,9 +223,10 @@ export type GetPlanItemPrice = {
*/
amount?: number | undefined;
/**
* Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
* Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
*/
tiers?: Array<GetPlanTier> | undefined;
tierBehavior?: GetPlanTierBehavior | undefined;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -365,6 +373,36 @@ export const GetPlanEnv = {
*/
export type GetPlanEnv = OpenEnum<typeof GetPlanEnv>;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export const GetPlanScenario = {
Scheduled: "scheduled",
Active: "active",
New: "new",
Renew: "renew",
Upgrade: "upgrade",
Downgrade: "downgrade",
Cancel: "cancel",
Expired: "expired",
PastDue: "past_due",
} as const;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export type GetPlanScenario = OpenEnum<typeof GetPlanScenario>;
export type GetPlanCustomerEligibility = {
/**
* Whether a free trial is available for this customer.
*/
trialAvailable?: boolean | undefined;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
scenario: GetPlanScenario;
};
/**
* A plan defines a set of features, pricing, and entitlements that can be attached to customers.
*/
@@ -425,6 +463,7 @@ export type GetPlanResponse = {
* If this is a variant, the ID of the base plan it was created from.
*/
baseVariantId: string | null;
customerEligibility?: GetPlanCustomerEligibility | undefined;
};
/** @internal */
@@ -642,10 +681,18 @@ export function getPlanToFromJSON(
/** @internal */
export const GetPlanTier$inboundSchema: z.ZodMiniType<GetPlanTier, unknown> = z
.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
});
.pipe(
z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
flat_amount: z.optional(z.nullable(types.number())),
}),
z.transform((v) => {
return remap$(v, {
"flat_amount": "flatAmount",
});
}),
);
export function getPlanTierFromJSON(
jsonString: string,
@@ -657,6 +704,12 @@ export function getPlanTierFromJSON(
);
}
/** @internal */
export const GetPlanTierBehavior$inboundSchema: z.ZodMiniType<
GetPlanTierBehavior,
unknown
> = openEnums.inboundSchema(GetPlanTierBehavior);
/** @internal */
export const GetPlanPriceItemInterval$inboundSchema: z.ZodMiniType<
GetPlanPriceItemInterval,
@@ -677,6 +730,7 @@ export const GetPlanItemPrice$inboundSchema: z.ZodMiniType<
z.object({
amount: types.optional(types.number()),
tiers: types.optional(z.array(z.lazy(() => GetPlanTier$inboundSchema))),
tier_behavior: types.optional(GetPlanTierBehavior$inboundSchema),
interval: GetPlanPriceItemInterval$inboundSchema,
interval_count: types.optional(types.number()),
billing_units: types.number(),
@@ -685,6 +739,7 @@ export const GetPlanItemPrice$inboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
"tier_behavior": "tierBehavior",
"interval_count": "intervalCount",
"billing_units": "billingUnits",
"billing_method": "billingMethod",
@@ -833,6 +888,38 @@ export function getPlanFreeTrialFromJSON(
export const GetPlanEnv$inboundSchema: z.ZodMiniType<GetPlanEnv, unknown> =
openEnums.inboundSchema(GetPlanEnv);
/** @internal */
export const GetPlanScenario$inboundSchema: z.ZodMiniType<
GetPlanScenario,
unknown
> = openEnums.inboundSchema(GetPlanScenario);
/** @internal */
export const GetPlanCustomerEligibility$inboundSchema: z.ZodMiniType<
GetPlanCustomerEligibility,
unknown
> = z.pipe(
z.object({
trial_available: types.optional(types.boolean()),
scenario: GetPlanScenario$inboundSchema,
}),
z.transform((v) => {
return remap$(v, {
"trial_available": "trialAvailable",
});
}),
);
export function getPlanCustomerEligibilityFromJSON(
jsonString: string,
): SafeParseResult<GetPlanCustomerEligibility, SDKValidationError> {
return safeParse(
jsonString,
(x) => GetPlanCustomerEligibility$inboundSchema.parse(JSON.parse(x)),
`Failed to parse 'GetPlanCustomerEligibility' from JSON`,
);
}
/** @internal */
export const GetPlanResponse$inboundSchema: z.ZodMiniType<
GetPlanResponse,
@@ -853,6 +940,9 @@ export const GetPlanResponse$inboundSchema: z.ZodMiniType<
env: GetPlanEnv$inboundSchema,
archived: types.boolean(),
base_variant_id: types.nullable(types.string()),
customer_eligibility: types.optional(
z.lazy(() => GetPlanCustomerEligibility$inboundSchema),
),
}),
z.transform((v) => {
return remap$(v, {
@@ -861,6 +951,7 @@ export const GetPlanResponse$inboundSchema: z.ZodMiniType<
"free_trial": "freeTrial",
"created_at": "createdAt",
"base_variant_id": "baseVariantId",
"customer_eligibility": "customerEligibility",
});
}),
);

View File

@@ -3,10 +3,10 @@
*/
export * from "./aggregate-events-op.js";
export * from "./attach-op.js";
export * from "./autumn-default-error.js";
export * from "./autumn-error.js";
export * from "./balance.js";
export * from "./billing-attach-op.js";
export * from "./billing-update-op.js";
export * from "./check-op.js";
export * from "./create-balance-op.js";
@@ -30,9 +30,11 @@ export * from "./list-customers-op.js";
export * from "./list-events-op.js";
export * from "./list-features-op.js";
export * from "./list-plans-op.js";
export * from "./multi-attach-op.js";
export * from "./open-customer-portal-op.js";
export * from "./plan.js";
export * from "./preview-attach-op.js";
export * from "./preview-multi-attach-op.js";
export * from "./preview-update-op.js";
export * from "./redeem-referral-code-op.js";
export * from "./response-validation-error.js";

View File

@@ -182,8 +182,15 @@ export type ListPlansTo = number | string;
export type ListPlansTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const ListPlansTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type ListPlansTierBehavior = OpenEnum<typeof ListPlansTierBehavior>;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -220,9 +227,10 @@ export type ListPlansItemPrice = {
*/
amount?: number | undefined;
/**
* Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
* Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
*/
tiers?: Array<ListPlansTier> | undefined;
tierBehavior?: ListPlansTierBehavior | undefined;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -369,6 +377,36 @@ export const ListPlansEnv = {
*/
export type ListPlansEnv = OpenEnum<typeof ListPlansEnv>;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export const ListPlansScenario = {
Scheduled: "scheduled",
Active: "active",
New: "new",
Renew: "renew",
Upgrade: "upgrade",
Downgrade: "downgrade",
Cancel: "cancel",
Expired: "expired",
PastDue: "past_due",
} as const;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export type ListPlansScenario = OpenEnum<typeof ListPlansScenario>;
export type ListPlansCustomerEligibility = {
/**
* Whether a free trial is available for this customer.
*/
trialAvailable?: boolean | undefined;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
scenario: ListPlansScenario;
};
/**
* A plan defines a set of features, pricing, and entitlements that can be attached to customers.
*/
@@ -429,6 +467,7 @@ export type ListPlansList = {
* If this is a variant, the ID of the base plan it was created from.
*/
baseVariantId: string | null;
customerEligibility?: ListPlansCustomerEligibility | undefined;
};
/**
@@ -667,10 +706,18 @@ export function listPlansToFromJSON(
export const ListPlansTier$inboundSchema: z.ZodMiniType<
ListPlansTier,
unknown
> = z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
});
> = z.pipe(
z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
flat_amount: z.optional(z.nullable(types.number())),
}),
z.transform((v) => {
return remap$(v, {
"flat_amount": "flatAmount",
});
}),
);
export function listPlansTierFromJSON(
jsonString: string,
@@ -682,6 +729,12 @@ export function listPlansTierFromJSON(
);
}
/** @internal */
export const ListPlansTierBehavior$inboundSchema: z.ZodMiniType<
ListPlansTierBehavior,
unknown
> = openEnums.inboundSchema(ListPlansTierBehavior);
/** @internal */
export const ListPlansPriceItemInterval$inboundSchema: z.ZodMiniType<
ListPlansPriceItemInterval,
@@ -702,6 +755,7 @@ export const ListPlansItemPrice$inboundSchema: z.ZodMiniType<
z.object({
amount: types.optional(types.number()),
tiers: types.optional(z.array(z.lazy(() => ListPlansTier$inboundSchema))),
tier_behavior: types.optional(ListPlansTierBehavior$inboundSchema),
interval: ListPlansPriceItemInterval$inboundSchema,
interval_count: types.optional(types.number()),
billing_units: types.number(),
@@ -710,6 +764,7 @@ export const ListPlansItemPrice$inboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
"tier_behavior": "tierBehavior",
"interval_count": "intervalCount",
"billing_units": "billingUnits",
"billing_method": "billingMethod",
@@ -860,6 +915,38 @@ export function listPlansFreeTrialFromJSON(
export const ListPlansEnv$inboundSchema: z.ZodMiniType<ListPlansEnv, unknown> =
openEnums.inboundSchema(ListPlansEnv);
/** @internal */
export const ListPlansScenario$inboundSchema: z.ZodMiniType<
ListPlansScenario,
unknown
> = openEnums.inboundSchema(ListPlansScenario);
/** @internal */
export const ListPlansCustomerEligibility$inboundSchema: z.ZodMiniType<
ListPlansCustomerEligibility,
unknown
> = z.pipe(
z.object({
trial_available: types.optional(types.boolean()),
scenario: ListPlansScenario$inboundSchema,
}),
z.transform((v) => {
return remap$(v, {
"trial_available": "trialAvailable",
});
}),
);
export function listPlansCustomerEligibilityFromJSON(
jsonString: string,
): SafeParseResult<ListPlansCustomerEligibility, SDKValidationError> {
return safeParse(
jsonString,
(x) => ListPlansCustomerEligibility$inboundSchema.parse(JSON.parse(x)),
`Failed to parse 'ListPlansCustomerEligibility' from JSON`,
);
}
/** @internal */
export const ListPlansList$inboundSchema: z.ZodMiniType<
ListPlansList,
@@ -880,6 +967,9 @@ export const ListPlansList$inboundSchema: z.ZodMiniType<
env: ListPlansEnv$inboundSchema,
archived: types.boolean(),
base_variant_id: types.nullable(types.string()),
customer_eligibility: types.optional(
z.lazy(() => ListPlansCustomerEligibility$inboundSchema),
),
}),
z.transform((v) => {
return remap$(v, {
@@ -888,6 +978,7 @@ export const ListPlansList$inboundSchema: z.ZodMiniType<
"free_trial": "freeTrial",
"created_at": "createdAt",
"base_variant_id": "baseVariantId",
"customer_eligibility": "customerEligibility",
});
}),
);

File diff suppressed because it is too large Load Diff

View File

@@ -163,8 +163,15 @@ export type PlanTo = number | string;
export type PlanTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const PlanTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type PlanTierBehavior = OpenEnum<typeof PlanTierBehavior>;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -199,9 +206,10 @@ export type PlanItemPrice = {
*/
amount?: number | undefined;
/**
* Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
* Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
*/
tiers?: Array<PlanTier> | undefined;
tierBehavior?: PlanTierBehavior | undefined;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -346,6 +354,36 @@ export const PlanEnv = {
*/
export type PlanEnv = OpenEnum<typeof PlanEnv>;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export const Scenario = {
Scheduled: "scheduled",
Active: "active",
New: "new",
Renew: "renew",
Upgrade: "upgrade",
Downgrade: "downgrade",
Cancel: "cancel",
Expired: "expired",
PastDue: "past_due",
} as const;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export type Scenario = OpenEnum<typeof Scenario>;
export type CustomerEligibility = {
/**
* Whether a free trial is available for this customer.
*/
trialAvailable?: boolean | undefined;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
scenario: Scenario;
};
export type Plan = {
/**
* Unique identifier for the plan.
@@ -403,6 +441,7 @@ export type Plan = {
* If this is a variant, the ID of the base plan it was created from.
*/
baseVariantId: string | null;
customerEligibility?: CustomerEligibility | undefined;
};
/** @internal */
@@ -593,11 +632,18 @@ export function planToFromJSON(
}
/** @internal */
export const PlanTier$inboundSchema: z.ZodMiniType<PlanTier, unknown> = z
.object({
export const PlanTier$inboundSchema: z.ZodMiniType<PlanTier, unknown> = z.pipe(
z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
});
flat_amount: z.optional(z.nullable(types.number())),
}),
z.transform((v) => {
return remap$(v, {
"flat_amount": "flatAmount",
});
}),
);
export function planTierFromJSON(
jsonString: string,
@@ -609,6 +655,12 @@ export function planTierFromJSON(
);
}
/** @internal */
export const PlanTierBehavior$inboundSchema: z.ZodMiniType<
PlanTierBehavior,
unknown
> = openEnums.inboundSchema(PlanTierBehavior);
/** @internal */
export const PlanPriceItemInterval$inboundSchema: z.ZodMiniType<
PlanPriceItemInterval,
@@ -629,6 +681,7 @@ export const PlanItemPrice$inboundSchema: z.ZodMiniType<
z.object({
amount: types.optional(types.number()),
tiers: types.optional(z.array(z.lazy(() => PlanTier$inboundSchema))),
tier_behavior: types.optional(PlanTierBehavior$inboundSchema),
interval: PlanPriceItemInterval$inboundSchema,
interval_count: types.optional(types.number()),
billing_units: types.number(),
@@ -637,6 +690,7 @@ export const PlanItemPrice$inboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
"tier_behavior": "tierBehavior",
"interval_count": "intervalCount",
"billing_units": "billingUnits",
"billing_method": "billingMethod",
@@ -780,6 +834,36 @@ export function freeTrialFromJSON(
export const PlanEnv$inboundSchema: z.ZodMiniType<PlanEnv, unknown> = openEnums
.inboundSchema(PlanEnv);
/** @internal */
export const Scenario$inboundSchema: z.ZodMiniType<Scenario, unknown> =
openEnums.inboundSchema(Scenario);
/** @internal */
export const CustomerEligibility$inboundSchema: z.ZodMiniType<
CustomerEligibility,
unknown
> = z.pipe(
z.object({
trial_available: types.optional(types.boolean()),
scenario: Scenario$inboundSchema,
}),
z.transform((v) => {
return remap$(v, {
"trial_available": "trialAvailable",
});
}),
);
export function customerEligibilityFromJSON(
jsonString: string,
): SafeParseResult<CustomerEligibility, SDKValidationError> {
return safeParse(
jsonString,
(x) => CustomerEligibility$inboundSchema.parse(JSON.parse(x)),
`Failed to parse 'CustomerEligibility' from JSON`,
);
}
/** @internal */
export const Plan$inboundSchema: z.ZodMiniType<Plan, unknown> = z.pipe(
z.object({
@@ -797,6 +881,9 @@ export const Plan$inboundSchema: z.ZodMiniType<Plan, unknown> = z.pipe(
env: PlanEnv$inboundSchema,
archived: types.boolean(),
base_variant_id: types.nullable(types.string()),
customer_eligibility: types.optional(z.lazy(() =>
CustomerEligibility$inboundSchema
)),
}),
z.transform((v) => {
return remap$(v, {
@@ -805,6 +892,7 @@ export const Plan$inboundSchema: z.ZodMiniType<Plan, unknown> = z.pipe(
"free_trial": "freeTrial",
"created_at": "createdAt",
"base_variant_id": "baseVariantId",
"customer_eligibility": "customerEligibility",
});
}),
);

View File

@@ -109,8 +109,17 @@ export type PreviewAttachTo = number | string;
export type PreviewAttachTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const PreviewAttachTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type PreviewAttachTierBehavior = ClosedEnum<
typeof PreviewAttachTierBehavior
>;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -152,9 +161,10 @@ export type PreviewAttachPrice = {
*/
amount?: number | undefined;
/**
* Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
* Tiered pricing. Either 'amount' or 'tiers' is required.
*/
tiers?: Array<PreviewAttachTier> | undefined;
tierBehavior?: PreviewAttachTierBehavior | undefined;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -450,6 +460,10 @@ export type PreviewAttachParams = {
* When the plan change should take effect. 'immediate' applies now, 'end_of_cycle' schedules for the end of the current billing cycle. By default, upgrades are immediate and downgrades are scheduled.
*/
planSchedule?: PreviewAttachPlanSchedule | undefined;
/**
* Additional parameters to pass into the creation of the Stripe checkout session.
*/
checkoutSessionParams?: { [k: string]: any } | undefined;
};
export type PreviewAttachDiscount = {
@@ -643,16 +657,25 @@ export function previewAttachToToJSON(
export type PreviewAttachTier$Outbound = {
to: number | string;
amount: number;
flat_amount?: number | null | undefined;
};
/** @internal */
export const PreviewAttachTier$outboundSchema: z.ZodMiniType<
PreviewAttachTier$Outbound,
PreviewAttachTier
> = z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
});
> = z.pipe(
z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.optional(z.nullable(z.number())),
}),
z.transform((v) => {
return remap$(v, {
flatAmount: "flat_amount",
});
}),
);
export function previewAttachTierToJSON(
previewAttachTier: PreviewAttachTier,
@@ -662,6 +685,11 @@ export function previewAttachTierToJSON(
);
}
/** @internal */
export const PreviewAttachTierBehavior$outboundSchema: z.ZodMiniEnum<
typeof PreviewAttachTierBehavior
> = z.enum(PreviewAttachTierBehavior);
/** @internal */
export const PreviewAttachItemPriceInterval$outboundSchema: z.ZodMiniEnum<
typeof PreviewAttachItemPriceInterval
@@ -676,6 +704,7 @@ export const PreviewAttachBillingMethod$outboundSchema: z.ZodMiniEnum<
export type PreviewAttachPrice$Outbound = {
amount?: number | undefined;
tiers?: Array<PreviewAttachTier$Outbound> | undefined;
tier_behavior?: string | undefined;
interval: string;
interval_count: number;
billing_units: number;
@@ -691,6 +720,7 @@ export const PreviewAttachPrice$outboundSchema: z.ZodMiniType<
z.object({
amount: z.optional(z.number()),
tiers: z.optional(z.array(z.lazy(() => PreviewAttachTier$outboundSchema))),
tierBehavior: z.optional(PreviewAttachTierBehavior$outboundSchema),
interval: PreviewAttachItemPriceInterval$outboundSchema,
intervalCount: z._default(z.number(), 1),
billingUnits: z._default(z.number(), 1),
@@ -699,6 +729,7 @@ export const PreviewAttachPrice$outboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
tierBehavior: "tier_behavior",
intervalCount: "interval_count",
billingUnits: "billing_units",
billingMethod: "billing_method",
@@ -1002,6 +1033,7 @@ export type PreviewAttachParams$Outbound = {
success_url?: string | undefined;
new_billing_subscription?: boolean | undefined;
plan_schedule?: string | undefined;
checkout_session_params?: { [k: string]: any } | undefined;
};
/** @internal */
@@ -1030,6 +1062,7 @@ export const PreviewAttachParams$outboundSchema: z.ZodMiniType<
successUrl: z.optional(z.string()),
newBillingSubscription: z.optional(z.boolean()),
planSchedule: z.optional(PreviewAttachPlanSchedule$outboundSchema),
checkoutSessionParams: z.optional(z.record(z.string(), z.any())),
}),
z.transform((v) => {
return remap$(v, {
@@ -1042,6 +1075,7 @@ export const PreviewAttachParams$outboundSchema: z.ZodMiniType<
successUrl: "success_url",
newBillingSubscription: "new_billing_subscription",
planSchedule: "plan_schedule",
checkoutSessionParams: "checkout_session_params",
});
}),
);

File diff suppressed because it is too large Load Diff

View File

@@ -109,8 +109,17 @@ export type PreviewUpdateTo = number | string;
export type PreviewUpdateTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const PreviewUpdateTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type PreviewUpdateTierBehavior = ClosedEnum<
typeof PreviewUpdateTierBehavior
>;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -152,9 +161,10 @@ export type PreviewUpdatePrice = {
*/
amount?: number | undefined;
/**
* Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
* Tiered pricing. Either 'amount' or 'tiers' is required.
*/
tiers?: Array<PreviewUpdateTier> | undefined;
tierBehavior?: PreviewUpdateTierBehavior | undefined;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -618,16 +628,25 @@ export function previewUpdateToToJSON(
export type PreviewUpdateTier$Outbound = {
to: number | string;
amount: number;
flat_amount?: number | null | undefined;
};
/** @internal */
export const PreviewUpdateTier$outboundSchema: z.ZodMiniType<
PreviewUpdateTier$Outbound,
PreviewUpdateTier
> = z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
});
> = z.pipe(
z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.optional(z.nullable(z.number())),
}),
z.transform((v) => {
return remap$(v, {
flatAmount: "flat_amount",
});
}),
);
export function previewUpdateTierToJSON(
previewUpdateTier: PreviewUpdateTier,
@@ -637,6 +656,11 @@ export function previewUpdateTierToJSON(
);
}
/** @internal */
export const PreviewUpdateTierBehavior$outboundSchema: z.ZodMiniEnum<
typeof PreviewUpdateTierBehavior
> = z.enum(PreviewUpdateTierBehavior);
/** @internal */
export const PreviewUpdateItemPriceInterval$outboundSchema: z.ZodMiniEnum<
typeof PreviewUpdateItemPriceInterval
@@ -651,6 +675,7 @@ export const PreviewUpdateBillingMethod$outboundSchema: z.ZodMiniEnum<
export type PreviewUpdatePrice$Outbound = {
amount?: number | undefined;
tiers?: Array<PreviewUpdateTier$Outbound> | undefined;
tier_behavior?: string | undefined;
interval: string;
interval_count: number;
billing_units: number;
@@ -666,6 +691,7 @@ export const PreviewUpdatePrice$outboundSchema: z.ZodMiniType<
z.object({
amount: z.optional(z.number()),
tiers: z.optional(z.array(z.lazy(() => PreviewUpdateTier$outboundSchema))),
tierBehavior: z.optional(PreviewUpdateTierBehavior$outboundSchema),
interval: PreviewUpdateItemPriceInterval$outboundSchema,
intervalCount: z._default(z.number(), 1),
billingUnits: z._default(z.number(), 1),
@@ -674,6 +700,7 @@ export const PreviewUpdatePrice$outboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
tierBehavior: "tier_behavior",
intervalCount: "interval_count",
billingUnits: "billing_units",
billingMethod: "billing_method",

View File

@@ -5,34 +5,415 @@
import * as z from "zod/v4-mini";
import { remap as remap$ } from "../lib/primitives.js";
import { safeParse } from "../lib/schemas.js";
import { ClosedEnum } from "../types/enums.js";
import { Result as SafeParseResult } from "../types/fp.js";
import * as types from "../types/primitives.js";
import {
CustomerData,
CustomerData$Outbound,
CustomerData$outboundSchema,
} from "./customer-data.js";
import { smartUnion } from "../types/smart-union.js";
import { SDKValidationError } from "./sdk-validation-error.js";
export type SetupPaymentGlobals = {
xApiVersion?: string | undefined;
};
/**
* Quantity configuration for a prepaid feature.
*/
export type SetupPaymentFeatureQuantity = {
/**
* The ID of the feature to set quantity for.
*/
featureId: string;
/**
* The quantity of the feature.
*/
quantity?: number | undefined;
/**
* Whether the customer can adjust the quantity.
*/
adjustable?: boolean | undefined;
};
/**
* Billing interval (e.g. 'month', 'year').
*/
export const SetupPaymentPriceInterval = {
OneOff: "one_off",
Week: "week",
Month: "month",
Quarter: "quarter",
SemiAnnual: "semi_annual",
Year: "year",
} as const;
/**
* Billing interval (e.g. 'month', 'year').
*/
export type SetupPaymentPriceInterval = ClosedEnum<
typeof SetupPaymentPriceInterval
>;
/**
* Base price configuration for a plan.
*/
export type SetupPaymentBasePrice = {
/**
* Base price amount for the plan.
*/
amount: number;
/**
* Billing interval (e.g. 'month', 'year').
*/
interval: SetupPaymentPriceInterval;
/**
* Number of intervals per billing cycle. Defaults to 1.
*/
intervalCount?: number | undefined;
};
/**
* Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
*/
export const SetupPaymentResetInterval = {
OneOff: "one_off",
Minute: "minute",
Hour: "hour",
Day: "day",
Week: "week",
Month: "month",
Quarter: "quarter",
SemiAnnual: "semi_annual",
Year: "year",
} as const;
/**
* Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
*/
export type SetupPaymentResetInterval = ClosedEnum<
typeof SetupPaymentResetInterval
>;
/**
* Reset configuration for consumable features. Omit for non-consumable features like seats.
*/
export type SetupPaymentReset = {
/**
* Interval at which balance resets (e.g. 'month', 'year'). For consumable features only.
*/
interval: SetupPaymentResetInterval;
/**
* Number of intervals between resets. Defaults to 1.
*/
intervalCount?: number | undefined;
};
export type SetupPaymentTo = number | string;
export type SetupPaymentTier = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const SetupPaymentTierBehavior = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type SetupPaymentTierBehavior = ClosedEnum<
typeof SetupPaymentTierBehavior
>;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
export const SetupPaymentItemPriceInterval = {
OneOff: "one_off",
Week: "week",
Month: "month",
Quarter: "quarter",
SemiAnnual: "semi_annual",
Year: "year",
} as const;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
export type SetupPaymentItemPriceInterval = ClosedEnum<
typeof SetupPaymentItemPriceInterval
>;
/**
* 'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
*/
export const SetupPaymentBillingMethod = {
Prepaid: "prepaid",
UsageBased: "usage_based",
} as const;
/**
* 'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
*/
export type SetupPaymentBillingMethod = ClosedEnum<
typeof SetupPaymentBillingMethod
>;
/**
* Pricing for usage beyond included units. Omit for free features.
*/
export type SetupPaymentPrice = {
/**
* Price per billing_units after included usage. Either 'amount' or 'tiers' is required.
*/
amount?: number | undefined;
/**
* Tiered pricing. Either 'amount' or 'tiers' is required.
*/
tiers?: Array<SetupPaymentTier> | undefined;
tierBehavior?: SetupPaymentTierBehavior | undefined;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
interval: SetupPaymentItemPriceInterval;
/**
* Number of intervals per billing cycle. Defaults to 1.
*/
intervalCount?: number | undefined;
/**
* Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200).
*/
billingUnits?: number | undefined;
/**
* 'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go.
*/
billingMethod: SetupPaymentBillingMethod;
/**
* Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total.
*/
maxPurchase?: number | undefined;
};
/**
* Billing behavior when quantity increases mid-cycle.
*/
export const SetupPaymentOnIncrease = {
BillImmediately: "bill_immediately",
ProrateImmediately: "prorate_immediately",
ProrateNextCycle: "prorate_next_cycle",
BillNextCycle: "bill_next_cycle",
} as const;
/**
* Billing behavior when quantity increases mid-cycle.
*/
export type SetupPaymentOnIncrease = ClosedEnum<typeof SetupPaymentOnIncrease>;
/**
* Credit behavior when quantity decreases mid-cycle.
*/
export const SetupPaymentOnDecrease = {
Prorate: "prorate",
ProrateImmediately: "prorate_immediately",
ProrateNextCycle: "prorate_next_cycle",
None: "none",
NoProrations: "no_prorations",
} as const;
/**
* Credit behavior when quantity decreases mid-cycle.
*/
export type SetupPaymentOnDecrease = ClosedEnum<typeof SetupPaymentOnDecrease>;
/**
* Proration settings for prepaid features. Controls mid-cycle quantity change billing.
*/
export type SetupPaymentProration = {
/**
* Billing behavior when quantity increases mid-cycle.
*/
onIncrease: SetupPaymentOnIncrease;
/**
* Credit behavior when quantity decreases mid-cycle.
*/
onDecrease: SetupPaymentOnDecrease;
};
/**
* When rolled over units expire.
*/
export const SetupPaymentExpiryDurationType = {
Month: "month",
Forever: "forever",
} as const;
/**
* When rolled over units expire.
*/
export type SetupPaymentExpiryDurationType = ClosedEnum<
typeof SetupPaymentExpiryDurationType
>;
/**
* Rollover config for unused units. If set, unused included units carry over.
*/
export type SetupPaymentRollover = {
/**
* Max rollover units. Omit for unlimited rollover.
*/
max?: number | undefined;
/**
* When rolled over units expire.
*/
expiryDurationType: SetupPaymentExpiryDurationType;
/**
* Number of periods before expiry.
*/
expiryDurationLength?: number | undefined;
};
/**
* Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings.
*/
export type SetupPaymentPlanItem = {
/**
* The ID of the feature to configure.
*/
featureId: string;
/**
* Number of free units included. Balance resets to this each interval for consumable features.
*/
included?: number | undefined;
/**
* If true, customer has unlimited access to this feature.
*/
unlimited?: boolean | undefined;
/**
* Reset configuration for consumable features. Omit for non-consumable features like seats.
*/
reset?: SetupPaymentReset | undefined;
/**
* Pricing for usage beyond included units. Omit for free features.
*/
price?: SetupPaymentPrice | undefined;
/**
* Proration settings for prepaid features. Controls mid-cycle quantity change billing.
*/
proration?: SetupPaymentProration | undefined;
/**
* Rollover config for unused units. If set, unused included units carry over.
*/
rollover?: SetupPaymentRollover | undefined;
};
/**
* Unit of time for the trial ('day', 'month', 'year').
*/
export const SetupPaymentDurationType = {
Day: "day",
Month: "month",
Year: "year",
} as const;
/**
* Unit of time for the trial ('day', 'month', 'year').
*/
export type SetupPaymentDurationType = ClosedEnum<
typeof SetupPaymentDurationType
>;
/**
* Free trial configuration for a plan.
*/
export type SetupPaymentFreeTrialParams = {
/**
* Number of duration_type periods the trial lasts.
*/
durationLength: number;
/**
* Unit of time for the trial ('day', 'month', 'year').
*/
durationType?: SetupPaymentDurationType | undefined;
/**
* If true, payment method required to start trial. Customer is charged after trial ends.
*/
cardRequired?: boolean | undefined;
};
/**
* Customize the plan to attach. Can override the price, items, free trial, or a combination.
*/
export type SetupPaymentCustomize = {
/**
* Override the base price of the plan. Pass null to remove the base price.
*/
price?: SetupPaymentBasePrice | null | undefined;
/**
* Override the items in the plan.
*/
items?: Array<SetupPaymentPlanItem> | undefined;
/**
* Override the plan's default free trial. Pass an object to set a custom trial, or null to remove the trial entirely.
*/
freeTrial?: SetupPaymentFreeTrialParams | null | undefined;
};
/**
* How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges.
*/
export const SetupPaymentProrationBehavior = {
ProrateImmediately: "prorate_immediately",
None: "none",
} as const;
/**
* How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges.
*/
export type SetupPaymentProrationBehavior = ClosedEnum<
typeof SetupPaymentProrationBehavior
>;
/**
* A discount to apply. Can be either a reward ID or a promotion code.
*/
export type SetupPaymentAttachDiscount = {
/**
* The ID of the reward to apply as a discount.
*/
rewardId?: string | undefined;
/**
* The promotion code to apply as a discount.
*/
promotionCode?: string | undefined;
};
export type SetupPaymentParams = {
/**
* The ID of the customer
* The ID of the customer to attach the plan to.
*/
customerId: string;
/**
* URL to redirect to after successful payment setup. Must start with either http:// or https://
* The ID of the entity to attach the plan to.
*/
entityId?: string | undefined;
/**
* If specified, the plan will be attached to the customer after setup.
*/
planId?: string | undefined;
/**
* If this plan contains prepaid features, use this field to specify the quantity of each prepaid feature. This quantity includes the included amount and billing units defined when setting up the plan.
*/
featureQuantities?: Array<SetupPaymentFeatureQuantity> | undefined;
/**
* The version of the plan to attach.
*/
version?: number | undefined;
/**
* Customize the plan to attach. Can override the price, items, free trial, or a combination.
*/
customize?: SetupPaymentCustomize | undefined;
/**
* How to handle proration when updating an existing subscription. 'prorate_immediately' charges/credits prorated amounts now, 'none' skips creating any charges.
*/
prorationBehavior?: SetupPaymentProrationBehavior | undefined;
/**
* List of discounts to apply. Each discount can be an Autumn reward ID, Stripe coupon ID, or Stripe promotion code.
*/
discounts?: Array<SetupPaymentAttachDiscount> | undefined;
/**
* URL to redirect to after successful checkout.
*/
successUrl?: string | undefined;
/**
* Customer details to set when creating a customer
*/
customerData?: CustomerData | undefined;
/**
* Additional parameters for the checkout session
* Additional parameters to pass into the creation of the Stripe checkout session.
*/
checkoutSessionParams?: { [k: string]: any } | undefined;
};
@@ -46,16 +427,472 @@ export type SetupPaymentResponse = {
*/
customerId: string;
/**
* URL to the payment setup page
* The ID of the entity the plan (if specified) will be attached to after setup.
*/
entityId?: string | undefined;
/**
* URL to redirect the customer to setup their payment.
*/
url: string;
};
/** @internal */
export type SetupPaymentFeatureQuantity$Outbound = {
feature_id: string;
quantity?: number | undefined;
adjustable?: boolean | undefined;
};
/** @internal */
export const SetupPaymentFeatureQuantity$outboundSchema: z.ZodMiniType<
SetupPaymentFeatureQuantity$Outbound,
SetupPaymentFeatureQuantity
> = z.pipe(
z.object({
featureId: z.string(),
quantity: z.optional(z.number()),
adjustable: z.optional(z.boolean()),
}),
z.transform((v) => {
return remap$(v, {
featureId: "feature_id",
});
}),
);
export function setupPaymentFeatureQuantityToJSON(
setupPaymentFeatureQuantity: SetupPaymentFeatureQuantity,
): string {
return JSON.stringify(
SetupPaymentFeatureQuantity$outboundSchema.parse(
setupPaymentFeatureQuantity,
),
);
}
/** @internal */
export const SetupPaymentPriceInterval$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentPriceInterval
> = z.enum(SetupPaymentPriceInterval);
/** @internal */
export type SetupPaymentBasePrice$Outbound = {
amount: number;
interval: string;
interval_count?: number | undefined;
};
/** @internal */
export const SetupPaymentBasePrice$outboundSchema: z.ZodMiniType<
SetupPaymentBasePrice$Outbound,
SetupPaymentBasePrice
> = z.pipe(
z.object({
amount: z.number(),
interval: SetupPaymentPriceInterval$outboundSchema,
intervalCount: z.optional(z.number()),
}),
z.transform((v) => {
return remap$(v, {
intervalCount: "interval_count",
});
}),
);
export function setupPaymentBasePriceToJSON(
setupPaymentBasePrice: SetupPaymentBasePrice,
): string {
return JSON.stringify(
SetupPaymentBasePrice$outboundSchema.parse(setupPaymentBasePrice),
);
}
/** @internal */
export const SetupPaymentResetInterval$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentResetInterval
> = z.enum(SetupPaymentResetInterval);
/** @internal */
export type SetupPaymentReset$Outbound = {
interval: string;
interval_count?: number | undefined;
};
/** @internal */
export const SetupPaymentReset$outboundSchema: z.ZodMiniType<
SetupPaymentReset$Outbound,
SetupPaymentReset
> = z.pipe(
z.object({
interval: SetupPaymentResetInterval$outboundSchema,
intervalCount: z.optional(z.number()),
}),
z.transform((v) => {
return remap$(v, {
intervalCount: "interval_count",
});
}),
);
export function setupPaymentResetToJSON(
setupPaymentReset: SetupPaymentReset,
): string {
return JSON.stringify(
SetupPaymentReset$outboundSchema.parse(setupPaymentReset),
);
}
/** @internal */
export type SetupPaymentTo$Outbound = number | string;
/** @internal */
export const SetupPaymentTo$outboundSchema: z.ZodMiniType<
SetupPaymentTo$Outbound,
SetupPaymentTo
> = smartUnion([z.number(), z.string()]);
export function setupPaymentToToJSON(setupPaymentTo: SetupPaymentTo): string {
return JSON.stringify(SetupPaymentTo$outboundSchema.parse(setupPaymentTo));
}
/** @internal */
export type SetupPaymentTier$Outbound = {
to: number | string;
amount: number;
flat_amount?: number | null | undefined;
};
/** @internal */
export const SetupPaymentTier$outboundSchema: z.ZodMiniType<
SetupPaymentTier$Outbound,
SetupPaymentTier
> = z.pipe(
z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.optional(z.nullable(z.number())),
}),
z.transform((v) => {
return remap$(v, {
flatAmount: "flat_amount",
});
}),
);
export function setupPaymentTierToJSON(
setupPaymentTier: SetupPaymentTier,
): string {
return JSON.stringify(
SetupPaymentTier$outboundSchema.parse(setupPaymentTier),
);
}
/** @internal */
export const SetupPaymentTierBehavior$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentTierBehavior
> = z.enum(SetupPaymentTierBehavior);
/** @internal */
export const SetupPaymentItemPriceInterval$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentItemPriceInterval
> = z.enum(SetupPaymentItemPriceInterval);
/** @internal */
export const SetupPaymentBillingMethod$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentBillingMethod
> = z.enum(SetupPaymentBillingMethod);
/** @internal */
export type SetupPaymentPrice$Outbound = {
amount?: number | undefined;
tiers?: Array<SetupPaymentTier$Outbound> | undefined;
tier_behavior?: string | undefined;
interval: string;
interval_count: number;
billing_units: number;
billing_method: string;
max_purchase?: number | undefined;
};
/** @internal */
export const SetupPaymentPrice$outboundSchema: z.ZodMiniType<
SetupPaymentPrice$Outbound,
SetupPaymentPrice
> = z.pipe(
z.object({
amount: z.optional(z.number()),
tiers: z.optional(z.array(z.lazy(() => SetupPaymentTier$outboundSchema))),
tierBehavior: z.optional(SetupPaymentTierBehavior$outboundSchema),
interval: SetupPaymentItemPriceInterval$outboundSchema,
intervalCount: z._default(z.number(), 1),
billingUnits: z._default(z.number(), 1),
billingMethod: SetupPaymentBillingMethod$outboundSchema,
maxPurchase: z.optional(z.number()),
}),
z.transform((v) => {
return remap$(v, {
tierBehavior: "tier_behavior",
intervalCount: "interval_count",
billingUnits: "billing_units",
billingMethod: "billing_method",
maxPurchase: "max_purchase",
});
}),
);
export function setupPaymentPriceToJSON(
setupPaymentPrice: SetupPaymentPrice,
): string {
return JSON.stringify(
SetupPaymentPrice$outboundSchema.parse(setupPaymentPrice),
);
}
/** @internal */
export const SetupPaymentOnIncrease$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentOnIncrease
> = z.enum(SetupPaymentOnIncrease);
/** @internal */
export const SetupPaymentOnDecrease$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentOnDecrease
> = z.enum(SetupPaymentOnDecrease);
/** @internal */
export type SetupPaymentProration$Outbound = {
on_increase: string;
on_decrease: string;
};
/** @internal */
export const SetupPaymentProration$outboundSchema: z.ZodMiniType<
SetupPaymentProration$Outbound,
SetupPaymentProration
> = z.pipe(
z.object({
onIncrease: SetupPaymentOnIncrease$outboundSchema,
onDecrease: SetupPaymentOnDecrease$outboundSchema,
}),
z.transform((v) => {
return remap$(v, {
onIncrease: "on_increase",
onDecrease: "on_decrease",
});
}),
);
export function setupPaymentProrationToJSON(
setupPaymentProration: SetupPaymentProration,
): string {
return JSON.stringify(
SetupPaymentProration$outboundSchema.parse(setupPaymentProration),
);
}
/** @internal */
export const SetupPaymentExpiryDurationType$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentExpiryDurationType
> = z.enum(SetupPaymentExpiryDurationType);
/** @internal */
export type SetupPaymentRollover$Outbound = {
max?: number | undefined;
expiry_duration_type: string;
expiry_duration_length?: number | undefined;
};
/** @internal */
export const SetupPaymentRollover$outboundSchema: z.ZodMiniType<
SetupPaymentRollover$Outbound,
SetupPaymentRollover
> = z.pipe(
z.object({
max: z.optional(z.number()),
expiryDurationType: SetupPaymentExpiryDurationType$outboundSchema,
expiryDurationLength: z.optional(z.number()),
}),
z.transform((v) => {
return remap$(v, {
expiryDurationType: "expiry_duration_type",
expiryDurationLength: "expiry_duration_length",
});
}),
);
export function setupPaymentRolloverToJSON(
setupPaymentRollover: SetupPaymentRollover,
): string {
return JSON.stringify(
SetupPaymentRollover$outboundSchema.parse(setupPaymentRollover),
);
}
/** @internal */
export type SetupPaymentPlanItem$Outbound = {
feature_id: string;
included?: number | undefined;
unlimited?: boolean | undefined;
reset?: SetupPaymentReset$Outbound | undefined;
price?: SetupPaymentPrice$Outbound | undefined;
proration?: SetupPaymentProration$Outbound | undefined;
rollover?: SetupPaymentRollover$Outbound | undefined;
};
/** @internal */
export const SetupPaymentPlanItem$outboundSchema: z.ZodMiniType<
SetupPaymentPlanItem$Outbound,
SetupPaymentPlanItem
> = z.pipe(
z.object({
featureId: z.string(),
included: z.optional(z.number()),
unlimited: z.optional(z.boolean()),
reset: z.optional(z.lazy(() => SetupPaymentReset$outboundSchema)),
price: z.optional(z.lazy(() => SetupPaymentPrice$outboundSchema)),
proration: z.optional(z.lazy(() => SetupPaymentProration$outboundSchema)),
rollover: z.optional(z.lazy(() => SetupPaymentRollover$outboundSchema)),
}),
z.transform((v) => {
return remap$(v, {
featureId: "feature_id",
});
}),
);
export function setupPaymentPlanItemToJSON(
setupPaymentPlanItem: SetupPaymentPlanItem,
): string {
return JSON.stringify(
SetupPaymentPlanItem$outboundSchema.parse(setupPaymentPlanItem),
);
}
/** @internal */
export const SetupPaymentDurationType$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentDurationType
> = z.enum(SetupPaymentDurationType);
/** @internal */
export type SetupPaymentFreeTrialParams$Outbound = {
duration_length: number;
duration_type: string;
card_required: boolean;
};
/** @internal */
export const SetupPaymentFreeTrialParams$outboundSchema: z.ZodMiniType<
SetupPaymentFreeTrialParams$Outbound,
SetupPaymentFreeTrialParams
> = z.pipe(
z.object({
durationLength: z.number(),
durationType: z._default(SetupPaymentDurationType$outboundSchema, "month"),
cardRequired: z._default(z.boolean(), true),
}),
z.transform((v) => {
return remap$(v, {
durationLength: "duration_length",
durationType: "duration_type",
cardRequired: "card_required",
});
}),
);
export function setupPaymentFreeTrialParamsToJSON(
setupPaymentFreeTrialParams: SetupPaymentFreeTrialParams,
): string {
return JSON.stringify(
SetupPaymentFreeTrialParams$outboundSchema.parse(
setupPaymentFreeTrialParams,
),
);
}
/** @internal */
export type SetupPaymentCustomize$Outbound = {
price?: SetupPaymentBasePrice$Outbound | null | undefined;
items?: Array<SetupPaymentPlanItem$Outbound> | undefined;
free_trial?: SetupPaymentFreeTrialParams$Outbound | null | undefined;
};
/** @internal */
export const SetupPaymentCustomize$outboundSchema: z.ZodMiniType<
SetupPaymentCustomize$Outbound,
SetupPaymentCustomize
> = z.pipe(
z.object({
price: z.optional(
z.nullable(z.lazy(() => SetupPaymentBasePrice$outboundSchema)),
),
items: z.optional(
z.array(z.lazy(() => SetupPaymentPlanItem$outboundSchema)),
),
freeTrial: z.optional(
z.nullable(z.lazy(() => SetupPaymentFreeTrialParams$outboundSchema)),
),
}),
z.transform((v) => {
return remap$(v, {
freeTrial: "free_trial",
});
}),
);
export function setupPaymentCustomizeToJSON(
setupPaymentCustomize: SetupPaymentCustomize,
): string {
return JSON.stringify(
SetupPaymentCustomize$outboundSchema.parse(setupPaymentCustomize),
);
}
/** @internal */
export const SetupPaymentProrationBehavior$outboundSchema: z.ZodMiniEnum<
typeof SetupPaymentProrationBehavior
> = z.enum(SetupPaymentProrationBehavior);
/** @internal */
export type SetupPaymentAttachDiscount$Outbound = {
reward_id?: string | undefined;
promotion_code?: string | undefined;
};
/** @internal */
export const SetupPaymentAttachDiscount$outboundSchema: z.ZodMiniType<
SetupPaymentAttachDiscount$Outbound,
SetupPaymentAttachDiscount
> = z.pipe(
z.object({
rewardId: z.optional(z.string()),
promotionCode: z.optional(z.string()),
}),
z.transform((v) => {
return remap$(v, {
rewardId: "reward_id",
promotionCode: "promotion_code",
});
}),
);
export function setupPaymentAttachDiscountToJSON(
setupPaymentAttachDiscount: SetupPaymentAttachDiscount,
): string {
return JSON.stringify(
SetupPaymentAttachDiscount$outboundSchema.parse(setupPaymentAttachDiscount),
);
}
/** @internal */
export type SetupPaymentParams$Outbound = {
customer_id: string;
entity_id?: string | undefined;
plan_id?: string | undefined;
feature_quantities?: Array<SetupPaymentFeatureQuantity$Outbound> | undefined;
version?: number | undefined;
customize?: SetupPaymentCustomize$Outbound | undefined;
proration_behavior?: string | undefined;
discounts?: Array<SetupPaymentAttachDiscount$Outbound> | undefined;
success_url?: string | undefined;
customer_data?: CustomerData$Outbound | undefined;
checkout_session_params?: { [k: string]: any } | undefined;
};
@@ -66,15 +903,28 @@ export const SetupPaymentParams$outboundSchema: z.ZodMiniType<
> = z.pipe(
z.object({
customerId: z.string(),
entityId: z.optional(z.string()),
planId: z.optional(z.string()),
featureQuantities: z.optional(
z.array(z.lazy(() => SetupPaymentFeatureQuantity$outboundSchema)),
),
version: z.optional(z.number()),
customize: z.optional(z.lazy(() => SetupPaymentCustomize$outboundSchema)),
prorationBehavior: z.optional(SetupPaymentProrationBehavior$outboundSchema),
discounts: z.optional(
z.array(z.lazy(() => SetupPaymentAttachDiscount$outboundSchema)),
),
successUrl: z.optional(z.string()),
customerData: z.optional(CustomerData$outboundSchema),
checkoutSessionParams: z.optional(z.record(z.string(), z.any())),
}),
z.transform((v) => {
return remap$(v, {
customerId: "customer_id",
entityId: "entity_id",
planId: "plan_id",
featureQuantities: "feature_quantities",
prorationBehavior: "proration_behavior",
successUrl: "success_url",
customerData: "customer_data",
checkoutSessionParams: "checkout_session_params",
});
}),
@@ -95,11 +945,13 @@ export const SetupPaymentResponse$inboundSchema: z.ZodMiniType<
> = z.pipe(
z.object({
customer_id: types.string(),
entity_id: types.optional(types.string()),
url: types.string(),
}),
z.transform((v) => {
return remap$(v, {
"customer_id": "customerId",
"entity_id": "entityId",
});
}),
);

View File

@@ -54,6 +54,10 @@ export type UpdateBalanceParams = {
* Add this amount to the current balance. Use negative values to subtract. Cannot be combined with current_balance.
*/
addToBalance?: number | undefined;
/**
* The usage amount to update. Cannot be combined with remaining or add_to_balance.
*/
usage?: number | undefined;
/**
* Target a specific balance by its reset interval. Use when the customer has multiple balances for the same feature with different reset intervals.
*/
@@ -79,6 +83,7 @@ export type UpdateBalanceParams$Outbound = {
entity_id?: string | undefined;
remaining?: number | undefined;
add_to_balance?: number | undefined;
usage?: number | undefined;
interval?: string | undefined;
};
@@ -93,6 +98,7 @@ export const UpdateBalanceParams$outboundSchema: z.ZodMiniType<
entityId: z.optional(z.string()),
remaining: z.optional(z.number()),
addToBalance: z.optional(z.number()),
usage: z.optional(z.number()),
interval: z.optional(UpdateBalanceInterval$outboundSchema),
}),
z.transform((v) => {

View File

@@ -92,8 +92,17 @@ export type UpdatePlanToRequest = number | string;
export type UpdatePlanTierRequest = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const UpdatePlanTierBehaviorRequest = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type UpdatePlanTierBehaviorRequest = ClosedEnum<
typeof UpdatePlanTierBehaviorRequest
>;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -135,9 +144,10 @@ export type UpdatePlanPriceRequest = {
*/
amount?: number | undefined;
/**
* Tiered pricing. Each tier's 'to' does NOT include included amount. Either 'amount' or 'tiers' is required.
* Tiered pricing. Either 'amount' or 'tiers' is required.
*/
tiers?: Array<UpdatePlanTierRequest> | undefined;
tierBehavior?: UpdatePlanTierBehaviorRequest | undefined;
/**
* Billing interval. For consumable features, should match reset.interval.
*/
@@ -499,8 +509,17 @@ export type UpdatePlanToResponse = number | string;
export type UpdatePlanTierResponse = {
to: number | string;
amount: number;
flatAmount?: number | null | undefined;
};
export const UpdatePlanTierBehaviorResponse = {
Graduated: "graduated",
Volume: "volume",
} as const;
export type UpdatePlanTierBehaviorResponse = OpenEnum<
typeof UpdatePlanTierBehaviorResponse
>;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -539,9 +558,10 @@ export type UpdatePlanItemPriceResponse = {
*/
amount?: number | undefined;
/**
* Tiered pricing configuration. Each tier's 'up_to' does NOT include the included amount. Either 'tiers' or 'amount' is required.
* Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required.
*/
tiers?: Array<UpdatePlanTierResponse> | undefined;
tierBehavior?: UpdatePlanTierBehaviorResponse | undefined;
/**
* Billing interval for this price. For consumable features, should match reset.interval.
*/
@@ -690,6 +710,36 @@ export const UpdatePlanEnv = {
*/
export type UpdatePlanEnv = OpenEnum<typeof UpdatePlanEnv>;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export const UpdatePlanScenario = {
Scheduled: "scheduled",
Active: "active",
New: "new",
Renew: "renew",
Upgrade: "upgrade",
Downgrade: "downgrade",
Cancel: "cancel",
Expired: "expired",
PastDue: "past_due",
} as const;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
export type UpdatePlanScenario = OpenEnum<typeof UpdatePlanScenario>;
export type UpdatePlanCustomerEligibility = {
/**
* Whether a free trial is available for this customer.
*/
trialAvailable?: boolean | undefined;
/**
* The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade).
*/
scenario: UpdatePlanScenario;
};
/**
* A plan defines a set of features, pricing, and entitlements that can be attached to customers.
*/
@@ -750,6 +800,7 @@ export type UpdatePlanResponse = {
* If this is a variant, the ID of the base plan it was created from.
*/
baseVariantId: string | null;
customerEligibility?: UpdatePlanCustomerEligibility | undefined;
};
/** @internal */
@@ -845,16 +896,25 @@ export function updatePlanToRequestToJSON(
export type UpdatePlanTierRequest$Outbound = {
to: number | string;
amount: number;
flat_amount?: number | null | undefined;
};
/** @internal */
export const UpdatePlanTierRequest$outboundSchema: z.ZodMiniType<
UpdatePlanTierRequest$Outbound,
UpdatePlanTierRequest
> = z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
});
> = z.pipe(
z.object({
to: smartUnion([z.number(), z.string()]),
amount: z.number(),
flatAmount: z.optional(z.nullable(z.number())),
}),
z.transform((v) => {
return remap$(v, {
flatAmount: "flat_amount",
});
}),
);
export function updatePlanTierRequestToJSON(
updatePlanTierRequest: UpdatePlanTierRequest,
@@ -864,6 +924,11 @@ export function updatePlanTierRequestToJSON(
);
}
/** @internal */
export const UpdatePlanTierBehaviorRequest$outboundSchema: z.ZodMiniEnum<
typeof UpdatePlanTierBehaviorRequest
> = z.enum(UpdatePlanTierBehaviorRequest);
/** @internal */
export const UpdatePlanItemPriceIntervalRequest$outboundSchema: z.ZodMiniEnum<
typeof UpdatePlanItemPriceIntervalRequest
@@ -878,6 +943,7 @@ export const UpdatePlanBillingMethodRequest$outboundSchema: z.ZodMiniEnum<
export type UpdatePlanPriceRequest$Outbound = {
amount?: number | undefined;
tiers?: Array<UpdatePlanTierRequest$Outbound> | undefined;
tier_behavior?: string | undefined;
interval: string;
interval_count: number;
billing_units: number;
@@ -895,6 +961,7 @@ export const UpdatePlanPriceRequest$outboundSchema: z.ZodMiniType<
tiers: z.optional(
z.array(z.lazy(() => UpdatePlanTierRequest$outboundSchema)),
),
tierBehavior: z.optional(UpdatePlanTierBehaviorRequest$outboundSchema),
interval: UpdatePlanItemPriceIntervalRequest$outboundSchema,
intervalCount: z._default(z.number(), 1),
billingUnits: z._default(z.number(), 1),
@@ -903,6 +970,7 @@ export const UpdatePlanPriceRequest$outboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
tierBehavior: "tier_behavior",
intervalCount: "interval_count",
billingUnits: "billing_units",
billingMethod: "billing_method",
@@ -1339,10 +1407,18 @@ export function updatePlanToResponseFromJSON(
export const UpdatePlanTierResponse$inboundSchema: z.ZodMiniType<
UpdatePlanTierResponse,
unknown
> = z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
});
> = z.pipe(
z.object({
to: smartUnion([types.number(), types.string()]),
amount: types.number(),
flat_amount: z.optional(z.nullable(types.number())),
}),
z.transform((v) => {
return remap$(v, {
"flat_amount": "flatAmount",
});
}),
);
export function updatePlanTierResponseFromJSON(
jsonString: string,
@@ -1354,6 +1430,12 @@ export function updatePlanTierResponseFromJSON(
);
}
/** @internal */
export const UpdatePlanTierBehaviorResponse$inboundSchema: z.ZodMiniType<
UpdatePlanTierBehaviorResponse,
unknown
> = openEnums.inboundSchema(UpdatePlanTierBehaviorResponse);
/** @internal */
export const UpdatePlanPriceItemIntervalResponse$inboundSchema: z.ZodMiniType<
UpdatePlanPriceItemIntervalResponse,
@@ -1376,6 +1458,7 @@ export const UpdatePlanItemPriceResponse$inboundSchema: z.ZodMiniType<
tiers: types.optional(
z.array(z.lazy(() => UpdatePlanTierResponse$inboundSchema)),
),
tier_behavior: types.optional(UpdatePlanTierBehaviorResponse$inboundSchema),
interval: UpdatePlanPriceItemIntervalResponse$inboundSchema,
interval_count: types.optional(types.number()),
billing_units: types.number(),
@@ -1384,6 +1467,7 @@ export const UpdatePlanItemPriceResponse$inboundSchema: z.ZodMiniType<
}),
z.transform((v) => {
return remap$(v, {
"tier_behavior": "tierBehavior",
"interval_count": "intervalCount",
"billing_units": "billingUnits",
"billing_method": "billingMethod",
@@ -1540,6 +1624,38 @@ export const UpdatePlanEnv$inboundSchema: z.ZodMiniType<
unknown
> = openEnums.inboundSchema(UpdatePlanEnv);
/** @internal */
export const UpdatePlanScenario$inboundSchema: z.ZodMiniType<
UpdatePlanScenario,
unknown
> = openEnums.inboundSchema(UpdatePlanScenario);
/** @internal */
export const UpdatePlanCustomerEligibility$inboundSchema: z.ZodMiniType<
UpdatePlanCustomerEligibility,
unknown
> = z.pipe(
z.object({
trial_available: types.optional(types.boolean()),
scenario: UpdatePlanScenario$inboundSchema,
}),
z.transform((v) => {
return remap$(v, {
"trial_available": "trialAvailable",
});
}),
);
export function updatePlanCustomerEligibilityFromJSON(
jsonString: string,
): SafeParseResult<UpdatePlanCustomerEligibility, SDKValidationError> {
return safeParse(
jsonString,
(x) => UpdatePlanCustomerEligibility$inboundSchema.parse(JSON.parse(x)),
`Failed to parse 'UpdatePlanCustomerEligibility' from JSON`,
);
}
/** @internal */
export const UpdatePlanResponse$inboundSchema: z.ZodMiniType<
UpdatePlanResponse,
@@ -1560,6 +1676,9 @@ export const UpdatePlanResponse$inboundSchema: z.ZodMiniType<
env: UpdatePlanEnv$inboundSchema,
archived: types.boolean(),
base_variant_id: types.nullable(types.string()),
customer_eligibility: types.optional(
z.lazy(() => UpdatePlanCustomerEligibility$inboundSchema),
),
}),
z.transform((v) => {
return remap$(v, {
@@ -1568,6 +1687,7 @@ export const UpdatePlanResponse$inboundSchema: z.ZodMiniType<
"free_trial": "freeTrial",
"created_at": "createdAt",
"base_variant_id": "baseVariantId",
"customer_eligibility": "customerEligibility",
});
}),
);

Some files were not shown because too many files have changed in this diff Show More