# Checkout and snippets

Three ways to take a payment, from no code to fully custom.

## Pay button

No server needed. Create a [payment link](/docs/payment-links), then paste:

```html
<script src="https://paylynks.io/js/button.js" data-link="YOUR_LINK_SLUG" data-label="Pay now" async></script>
```

Optional `data-color="#0f766e"` and `data-target="_self"`. The slug is the part after `/pay/` in the link URL.

## Embedded checkout

Create a payment intent on your server and pass its `client_secret` to the page:

```html
<script src="https://paylynks.io/js/v1.js"></script>
<div id="checkout"></div>
<script>
  PayLynks().mountCheckout("#checkout", {
    clientSecret: "pi_..._secret_...",
    onSuccess: (e) => console.log("paid", e.payment_intent, e.amount_total),
    onFailure: (e) => console.log(e.message),
    onReady: () => {},
  });
</script>
```

The checkout iframe collects the card, shows any surcharge disclosure and the final total, and charges. Your page gets events only from the PayLynks origin.

## Next.js

`npx paylynks init` writes these for you. The server route (prices stay on the server):

```ts
// app/api/paylynks/checkout/route.ts
const PRODUCTS: Record<string, { amount: number; description: string }> = {
  demo: { amount: 2500, description: "Demo product" },
};

export async function POST(request: Request) {
  const { product } = await request.json();
  const item = PRODUCTS[product];
  if (!item) return Response.json({ error: "Unknown product" }, { status: 400 });
  const res = await fetch("https://paylynks.io/api/v1/payment_intents", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.PAYLYNKS_SECRET_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify(item),
  });
  const data = await res.json();
  if (!res.ok) return Response.json({ error: data.error?.message }, { status: 502 });
  return Response.json({ clientSecret: data.client_secret });
}
```

And in a page: `<PayLynksCheckout product="demo" />`. Get the full component with the MCP tool `get_snippet` (`kind: "nextjs"`).

## React / Vite (Lovable, Bolt) with Supabase

These apps have no server of their own, so create the intent in a Supabase Edge Function (`get_snippet` kind `supabase`), set the key with `supabase secrets set PAYLYNKS_SECRET_KEY=sk_test_...`, and use the React component (`get_snippet` kind `react`):

```jsx
<PayLynksCheckout checkoutUrl="https://<project>.supabase.co/functions/v1/paylynks-checkout" product="demo" />
```

## Express

`get_snippet` kind `node` gives a `POST /api/paylynks/checkout` route.
