# Next.js

Attribute a Stripe customer from a server action with the App Router.

In a server action or a route handler, `cookies()` from `next/headers` gives you the cookie;
the rest is the same three lines.

```ts
"use server";

import { cookies } from "next/headers";
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

/** The click id from the `rail_referral` cookie, or null when the visitor had no referral. */
async function railReferral(): Promise<string | null> {
  const raw = (await cookies()).get("rail_referral")?.value;
  if (!raw) return null;
  try {
    return (JSON.parse(decodeURIComponent(raw)) as { clickId?: string }).clickId ?? null;
  } catch {
    return null;
  }
}

export async function startSubscription(formData: FormData) {
  const clickId = await railReferral();

  const customer = await stripe.customers.create({
    email: String(formData.get("email")),
    metadata: clickId ? { rail_referral: clickId } : {},
  });

  const subscription = await stripe.subscriptions.create({
    customer: customer.id,
    items: [{ price: process.env.STRIPE_PRICE_ID! }],
    payment_behavior: "default_incomplete",
    expand: ["latest_invoice.payment_intent"],
  });

  // Hand the client secret to Stripe Elements on the client; the sale is attributed when the
  // invoice pays, because the customer carries the referral.
  const invoice = subscription.latest_invoice as Stripe.Invoice & { payment_intent: Stripe.PaymentIntent };
  return { clientSecret: invoice.payment_intent.client_secret };
}
```

The cookie is set on your registrable domain, so a marketing site on `www.acme.com` and an app
on `app.acme.com` share it without any handoff. If the app lives on a different registrable
domain (`getacme.io`), list it in the script tag's `data-domains` attribute on the marketing site
and the script carries the referral across in the link.
