llms.txt
llms.txt

Autumn Integration

Autumn fits apps that want product-led billing without building every plan, entitlement, and usage event by hand.

Install from the CLI

farm add integration autumn --ui

Config-first setup

src/lib/integrations.ts
import { autumn } from "@farm.js/integrations/autumn";export const integrations = {  billing: autumn({    secretKey: process.env.AUTUMN_SECRET_KEY,    billing: {      resolveOwner(ctx) {        const userId = ctx.req.get<string>("user.id");        return userId ? { id: userId, kind: "user" } : null;      },    },  }),};

AUTUMN_WEBHOOK_SECRET is read from the environment when webhook routes are configured.

Choose SDK ownership

Let Farm construct Autumn

The config-first example is the default path. When instance is omitted, Farm creates the Autumn SDK from secretKey and optional serverURL, supplied directly or through environment variables where supported.

Provide an application-owned instance

import { Autumn } from "autumn-js";import { autumn } from "@farm.js/integrations/autumn";const autumnClient = new Autumn({  secretKey: process.env.AUTUMN_SECRET_KEY,});export const billing = autumn({  instance: autumnClient,  billing: {    resolveOwner: () => null,  },});

The instance wins if a secret key is also supplied. Billing, webhook, route, product, meter, and storage settings remain integration options in either mode.

Usage

const checkout = await api.billing.checkout.post({  body: {    productId: "pro",    customerId: user.id,    successPath: "/dashboard",  },});

Database-backed billing

The integration can persist customer, plan, entitlement, and usage records through ctx.args.db, so the app keeps the same integration surface when the database client changes. This schema-backed path is separate from KV storage.

What Autumn adds

Area Details
Products Public products for pricing pages.
Status Current plan, subscription, trial, features, limits, and entitlements.
Checkout Attach an Autumn product and redirect users when payment or confirmation is required.
Portal Open the customer portal from a typed caller.
Usage Meter usage, report usage, check balance, and read current charges.
Webhooks Verify Autumn events and keep local billing state in sync.

Common callers

const products = await api.billing.products.get();const status = await api.billing.status.get();const allowed = await api.billing.check.post({  body: {    key: "ai-generations",    amount: 1,  },});

Checkout flow

const checkout = await api.billing.checkout.post({  body: {    productId: "pro",    successPath: "/dashboard",    metadata: {      source: "pricing",    },  },});if (checkout.data?.redirectTo) {  window.location.href = checkout.data.redirectTo;}

Owner and entitlements

Autumn needs a billing owner when it checks or attaches customer state. Use the owner resolver to connect Farm auth/session data with Autumn customers.

autumn({  secretKey: process.env.AUTUMN_SECRET_KEY,  billing: {    async resolveOwner(ctx) {      const organizationId = ctx.req.get<string>("organization.id");      return organizationId        ? {            id: organizationId,            kind: "organization",            email: ctx.req.get<string>("user.email") ?? null,          }        : null;    },  },});

Production notes

  • Set AUTUMN_SECRET_KEY, AUTUMN_WEBHOOK_SECRET, and APP_BASE_URL.
  • Keep Farm product IDs separate from provider IDs when you want a stable app contract.
  • Use check before expensive operations and reportUsage after successful work.
  • Treat webhooks as the source of truth for subscription state.
  • Test free-plan reads, checkout redirects, portal redirects, usage limits, and webhook sync.