Skip to main content
Your autumn.config.ts file is the source of truth for your pricing. It builds features, plans and rewards with helper functions from the atmn package, and hands them to atmn() as the default export.
autumn.config.ts
Preview changes with atmn push, apply them with atmn push --yes, or pull what’s in Autumn with atmn pull.

File layout

atmn init and atmn pull create a folder with one file per kind of thing, and a root config that imports them:
atmn pull writes into these files and keeps your formatting. A single autumn.config.ts with everything in it works too. Any file that imports from atmn is treated as part of your config.

atmn(config)

The root of your config. Each list you include is the complete list: anything in Autumn that isn’t in it gets deleted on push. Leave a list out to leave that part of Autumn alone.
Feature[]
Every feature, from feature().
Plan[]
Every plan and every version of it, from plan().
Reward[]
Coupons and feature grants, from coupon() and featureGrant(). See rewards.
ReferralProgram[]
Referral programs, from referralProgram(). See referral programs.
object
Organization settings. Only the flags you state are changed. See settings.
The CLI checks the whole config before sending anything and reports every problem at once, with the file and line to fix.

Features

Features define what can be gated, metered or billed in your app.

feature(config)

string
required
Unique identifier used in API calls (check, track, etc).
string
required
Display name shown in the dashboard and billing UI.
enum
required
"boolean" | "metered" | "credit_system" | "ai_credit_system"
boolean
Required for metered features.
  • true: usage is used up and refilled (messages, API calls, credits)
  • false: usage is ongoing (seats, storage, workspaces)
array
Required for credit_system features. The rate card: one entry per metered feature that draws from the credit balance.Flat rate: { meteredFeatureId: string, creditCost: number, billingUnits?: number }: creditCost credits per billingUnits units (default 1).Graduated rate: { meteredFeatureId, billingUnits?, tierBehavior: "graduated", tiers: [{ to: number | "inf", creditCost: number }] }: the credit cost steps as usage in the cycle grows. The last tier must be "inf".Each entry may also carry dimensions and multipliers to price by event properties. See Rate cards and dimensions.
number
For ai_credit_system features. Percentage added on top of the model’s cost, eg 30. Use -100 to make usage free.
object
For ai_credit_system features. Markup per provider, keyed by the first part of the model ID: { openrouter: { markup: 25 } }.
object
For ai_credit_system features. Markup per model, keyed by model ID: { "openai/gpt-4o-mini": { markup: 20 } }. For your own models, add inputCost and outputCost in dollars per million tokens. See AI credit systems.
boolean
Archive the feature. Leave it out to keep it as is.
string
Written by the CLI after a push. Leave it there. Changing featureId next to it renames the feature.
object
Stripe mapping: { stripe: { productId, meterId } }. Only pulled with atmn pull --include-mappings.

Feature types

Boolean: simple on/off flag.
Metered, consumable: used up and refilled (messages, API calls).
Metered, non-consumable: ongoing usage (seats, storage).
Credit system: maps several metered features to credit costs.
If you set the price per credit to 1 cent, credits become monetary credits (eg, 5 credits = $0.05 per premium message).
AI credit system: bills LLM usage at the model’s real cost plus a markup. Track usage with track_tokens.

Plans

Plans combine features with pricing to create your subscription tiers, add-ons and top-ups.

plan(config)

string
required
Unique identifier used in checkout and subscription APIs.
string
required
Name of this version of the plan, eg "v1". See versions.
boolean
required
Whether this is the version new customers get. Exactly one version of each plan is active.
string
required
Display name shown in pricing tables and billing.
string
Optional description of the plan.
object
Base subscription price:
  • amount: number: price amount (eg, 20 for $20)
  • interval: string: "week" | "month" | "quarter" | "semi_annual" | "year" | "one_off"
  • intervalCount?: number: intervals per billing cycle, eg 3 with "month" for every 3 months. Defaults to 1.
  • additionalCurrencies?: array: amounts in other currencies, eg [{ currency: "eur", amount: 18 }]
array
Array of plan items defining what’s included. See plan items.
boolean
default:"false"
Automatically assign this plan to new customers. Typically used for free plans.
boolean
default:"false"
Allow this plan to be bought alongside other plans (instead of replacing them).
object
Free trial before billing starts:
  • durationLength: number: eg, 14
  • durationType: string: "day" | "month" | "year"
  • cardRequired: boolean: whether a card is needed to start the trial
  • onEnd?: string: "bill" (default) charges the customer when the trial ends. "revert" puts them back on their previous plan.
string
Group related plans together. Plans in the same group replace each other on upgrade/downgrade.
array
variant() entries for this plan, eg an annual version. See plan variants.
array
license() entries for plans this plan hands out per seat. See licenses.
object
Default billing controls for every customer on this plan: autoTopups, spendLimits, usageLimits, usageAlerts and overageAllowed. Each is an array with one entry per feature, using the same fields as the API.
object
{ ignorePastDue: true } keeps this plan’s balances resetting on schedule even when the customer is past due. { anchorToMonthStart: true } bills and resets on the 1st of each month (UTC). Leave config out to manage these flags elsewhere; once stated, it is the full set, so a flag it leaves out is off and config: {} turns them all off.
object
Any key-value data you want to keep on the plan. Shared by all versions.
boolean
Archive the plan. Leave it out to keep it as is.
string
Written by the CLI after a push. Leave it there. Changing planId next to it renames the plan.
object
Stripe and RevenueCat mappings: { stripe: { productId, additionalProductIds }, revenuecat: { products } }. Only pulled with atmn pull --include-mappings.

Versions

Each version of a plan is its own plan() entry with the same planId and a different versionSlug. One version is active: true; that’s the one new customers get. Customers on an older version stay on it. To change a plan’s price for new customers only, add a new version and set the old one to active: false:
To change a plan for everyone on it, edit its existing entry instead. If customers are on that version, Autumn drafts a migration and atmn push prints the link to run it.
After a push, the CLI adds an internalId to each plan and feature in your config. Leave it there. It’s how the CLI knows to rename a plan instead of deleting and recreating it.

Plan items

Plan items define what each plan includes: usage limits, pricing and billing behavior. They are plain objects in the plan’s items array.
string
required
The featureId of the feature to include.
number
Amount included for free. Leave it out for boolean features.
boolean
Give unlimited usage of this feature.
object
How often the included amount refills:
  • interval: string: "minute" | "hour" | "day" | "week" | "month" | "quarter" | "semi_annual" | "year" | "one_off"
  • intervalCount: number: defaults to 1
object
Pricing for usage beyond the included amount. See pricing patterns below.
object
How to handle mid-cycle quantity changes on prepaid items:
  • onIncrease: "prorate_immediately" | "bill_immediately" | "prorate_next_cycle" | "bill_next_cycle"
  • onDecrease: "prorate_immediately" | "prorate_next_cycle" | "no_prorations"
Leave it out to prorate immediately on both. pull only writes it when a plan uses something else.
object
Carry unused balance forward:
  • max: number: maximum rollover amount. Leave it out for no limit.
  • maxPercentage: number: maximum as a percentage (0-100) of the included amount. Use this or max, not both.
  • expiryDurationType: "month" | "forever"
  • expiryDurationLength: number: ignored if type is "forever"
object
{ threshold: number }: bill this many units each time unpaid usage reaches it, instead of waiting for the end of the cycle. Flat usage-based prices only.
boolean
default:"false"
For entity plans: pool every entity’s balance for this feature into one shared customer balance.
object
Override the feature’s settings for customers on this plan. For credit systems, { creditSchema: [...] } replaces the rate card. For AI credit systems, { markups: { defaultMarkup, providerMarkups, modelMarkups } } replaces the markups.

Pricing patterns

The price object on a plan item supports different billing models: Usage-based: charge based on actual usage.
Prepaid: customer buys a fixed quantity upfront.
Tiered: price changes based on usage volume.

Price fields

number
Price per billingUnits. Use this or tiers, not both.
array
Tiered pricing. Each entry: { to: number | "inf", amount: number, flatAmount?: number }. flatAmount adds a fixed charge for the tier. Use this or amount, not both.
enum
default:"graduated"
"graduated": each tier is priced at its own rate. "volume": the tier the total lands in prices everything. See volume-based tiers.
array
Amounts in other currencies. For flat prices: [{ currency: "eur", amount: 0.09 }] at the price level. For tiered prices, set per tier: { to: 1000, amount: 0.01, additionalCurrencies: [{ currency: "eur", amount: 0.009 }] }.
enum
required
"usage_based" | "prepaid"
enum
required
"week" | "month" | "quarter" | "semi_annual" | "year" | "one_off". Use "one_off" for one-time charges.
number
default:"1"
Intervals per billing cycle, eg 3 with "month" to bill every 3 months.
number
default:"1"
Units per price. Eg, $5 per 100 credits = amount: 5, billingUnits: 100.
number
Maximum quantity that can be bought.

Plan variants

A variant is a plan that starts from another plan and changes a few things, eg an annual version of Pro. Each one is a variant() entry listed in the base plan’s variants. See plan variants for how they work.

variant(config)

string
required
The variant’s own plan ID, eg "pro_annual".
string
required
Name of this version of the variant, eg "v1".
string
required
Display name, eg "Pro Annual".
object
What the variant changes from the base plan:
  • price: a new base price, or null to remove it
  • items: replaces the whole items list
  • addItems / removeItems: add plan items, or remove the base plan’s by { featureId, billingMethod?, interval? }. Use these instead of items to change only some items.
  • freeTrial: a different trial, or null for none
  • billingControls: different default billing controls
  • upsertLicenses / removeLicenses: change the base plan’s licenses
boolean
Archive the variant. Leave it out to keep it as is.
string
Written by the CLI after a push. Leave it there.

Licenses

A license links a plan to another plan that each seat gets, eg a Team plan that hands out a Seat plan per member. Each one is a license() entry in the parent plan’s licenses. See entity plans.

license(config)

string
required
The planId of the plan each seat gets.
string
required
Which version of that plan, eg "v1".
number
Number of seats included for free.
boolean
Cap seats at the included amount. Must be true for now.
object
Change what a seat gets on this parent plan: price, addItems and removeItems, with the same shapes as variants.

Rewards

Rewards are discounts and free usage that customers unlock with a promo code, or through a referral program. They go in the rewards list. See rewards and referrals.

coupon(config)

A discount on invoices.
string
required
Unique identifier for the coupon.
string
required
Display name.
enum
required
"percentage_discount" | "fixed_discount"
number
required
The percentage off (up to 100) or the fixed amount off.
object
required
How long it applies: { type: "one_off" | "months" | "forever", length: number | null }. length is the number of months for "months", and null otherwise.
string[] | null
required
Plans the coupon applies to, or null for all plans.
array
required
Codes customers can redeem: [{ code: "SAVE20", globalMaxRedemption?: number | null, firstTimeTransaction?: boolean | null }].

featureGrant(config)

Free usage of one or more features, unlocked with a promo code.
string
required
Unique identifier for the grant.
string
required
Display name.
array
required
What the customer gets: [{ featureId, included: number | null, expiry: { type: "day" | "week" | "month" | "year", length: number } | null }]. Use included: null for boolean features and expiry: null for a grant that never expires.
array
required
Codes customers can redeem: [{ code: "WELCOME", maxUses: number | null }]. null means unlimited uses.

Referral programs

A referral program gives a reward to customers who bring in new customers. They go in the referralPrograms list.

referralProgram(config)

string
required
Unique identifier, used when creating and redeeming referral codes.
string
required
The id of the coupon or feature grant to give, as a string. coupon() and featureGrant() return a wrapped entry, so you can’t read .id off them.
enum
required
When the reward is given: "customer_creation" (when the new customer signs up) or "checkout" (when they buy a plan).
enum
required
Who gets the reward: "referrer" only, or "all" (both the referrer and the new customer).
number | null
How many times one referrer can be rewarded. null for no limit.
string[] | null
Plans that trigger the reward. Required when redeemOn is "checkout".
boolean
Skip the reward when the new customer starts a trial.

Settings

The settings block manages organization-wide flags. Only the flags you state are changed. If you stop stating a flag, it keeps its current value; to turn one off, state it as false.
All default to false.

Full example

A complete config with a free plan, a paid plan with a trial, and a credits top-up add-on:
autumn.config.ts