Skip to main content

Overview

Autumn manages products, usage limits, and Stripe checkout on our behalf. The Fastify server only has to expose one proxy route and identify the current customer. Follow the official Autumn setup guide to configure products and API keys, then wire the identify handler described below to finish the integration.
Autumn automatically provisions customers when it receives a new customerId, so we simply forward the 8call user or organization identifier alongside basic profile metadata.

Prerequisites

  • autumn-js is installed in both the server and web workspaces.
  • The .env file contains AUTUMN_SECRET_KEY for server-side calls and the frontend is wrapped in <AutumnProvider>.
  • Supabase auth is configured so getUserFromRequest can resolve the authenticated profile.

Register the Fastify handler

1

Import the handler

Add the autumn-js Fastify adapter alongside the existing infrastructure imports.
-import fastifyMultipart from '@fastify/multipart';
+import fastifyMultipart from '@fastify/multipart';
+import { autumnHandler } from 'autumn-js/fastify';
2

Expose `/api/autumn/*`

Mount the handler in apps/server/index.ts so every GET or POST request under /api/autumn is forwarded to Autumn.
fastify.route({
  method: ['GET', 'POST'],
  url: '/api/autumn/*',
  handler: autumnHandler({
    identify: async (request) => {
      const typedRequest = request as FastifyRequest & { user?: ProfileAndOrganization };
      const existingUser = typedRequest.user;
      const user = existingUser ?? (await getUserFromRequest(request));

      if (!user || !user.profile) {
        throw handleNotAuthenticated();
      }

      const nameFallbacks = [
        user.profile.display_name,
        [user.profile.first_name, user.profile.last_name].filter(Boolean).join(' ').trim(),
        user.user_metadata?.name,
        user.user_metadata?.full_name,
      ].filter((value) => Boolean(value && `${value}`.trim()));

      return {
        customerId: user.profile.customer_id ?? user.id,
        customerData: {
          name: nameFallbacks[0] ?? undefined,
          email: user.profile.email ?? user.email,
        },
      };
    },
  }),
});
customerId defaults to the user ID if we have not yet synced the Supabase profile’s customer_id. Autumn will create the customer automatically on first contact.

Verify the proxy

curl -X GET "http://localhost:9000/api/autumn/customer" \
  -H "x-user-token: <supabase-session-token>"
{
  "customer": {
    "id": "user_123",
    "products": [...],
    "features": {...}
  }
}
  • 401 Not authenticated: Ensure the browser sends an Authorization or x-user-token header so getUserFromRequest can fetch the profile.
  • Missing customer data: Confirm the Supabase profile includes customer_id, or allow Autumn to create one on first request.
  • CORS errors from Vite dev: Add http://localhost:3000 to the Fastify CORS allowlist if you are proxying from the web app.