Guides / Payments

How to Track Stripe Payment Link Conversions

3 min readยทPayments

Stripe Payment Links fire the same checkout.session.completed event as regular checkouts. The payment_link field tells you which link was used.

Webhook handler

ts
// app/api/webhooks/stripe/route.ts
import Stripe from "stripe";
import { logit } from "@/lib/logit";

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

export async function POST(req: Request) {
  const body = await req.text();
  const sig = req.headers.get("stripe-signature")!;
  const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);

  if (event.type === "checkout.session.completed") {
    const session = event.data.object as Stripe.Checkout.Session;

    // Only handle Payment Link sessions
    if (session.payment_link) {
      const amount = (session.amount_total ?? 0) / 100;
      const currency = (session.currency ?? "usd").toUpperCase();

      // Fetch the payment link to get its label
      const link = await stripe.paymentLinks.retrieve(session.payment_link as string);

      await logit.now("payment-links", {
        event: "Payment link conversion",
        description: `${session.customer_details?.email ?? "Unknown"} โ€” $${amount.toFixed(2)} ${currency}`,
        icon: "๐Ÿ”—",
        notify: true,
        tags: {
          linkId: session.payment_link as string,
          currency: session.currency ?? "usd",
        },
        metadata: {
          sessionId: session.id,
          paymentLinkId: session.payment_link,
          amount,
          currency,
          email: session.customer_details?.email,
          linkUrl: link.url,
        },
      });
    }
  }

  return new Response("ok");
}

If you have different payment links for different products or pricing pages, use a channel per link:

ts
const channelMap: Record<string, string> = {
  "plink_starter": "payment-links-starter",
  "plink_pro": "payment-links-pro",
  "plink_enterprise": "payment-links-enterprise",
};

const channel = channelMap[session.payment_link as string] ?? "payment-links";

await logit.now(channel, {
  event: "Payment link conversion",
  // ...
});

Required webhook events

In your Stripe Dashboard โ†’ Webhooks, enable:

  • checkout.session.completed
  • payment_link.created (optional โ€” to track when links are created)

Try LogIt free

7-day trial. No credit card required.

Start free