A Stripe Payment Link is a hosted checkout page you create in the Stripe Dashboard without code. Make a product with a price, create the link, then put it behind a button on your site. You can redirect buyers to your own thank-you page after paying and add parameters to the link to prefill the email or tag the sale.
| Option | Code needed | Best for |
|---|---|---|
| Payment Link | None; share or link a URL | Selling a few products, invoices by link, social bios |
| Buy Button | Paste one script and one tag | A Stripe-styled button embedded on your page |
| Checkout (API) | Server code creates each session | Carts, per-customer prices, logged-in apps |
Updated
This guide covers the setup in the Dashboard, three ways to put the link on a website, the redirect to your own success page, link parameters for prefilling and tracking, and the settings people miss: tax, quantities and promotion codes.
Replace the href with your own link. Each button is a plain link, so it works on any site builder that accepts HTML.
A bold full-width button on phones that shrinks to fit on wider screens.
<a class="pay-btn" href="https://buy.stripe.com/your-link-id">
Buy the template <span>$29</span>
</a>
<style>
.pay-btn { display: inline-flex; gap: 10px; align-items: center; justify-content: center;
padding: 14px 26px; border-radius: 999px; background: #4f46e5; color: #fff;
font: 600 17px system-ui, sans-serif; text-decoration: none; }
.pay-btn span { background: rgb(255 255 255 / .18); padding: 2px 10px; border-radius: 999px; }
.pay-btn:hover { background: #4338ca; }
.pay-btn:focus-visible { outline: 3px solid #a5b4fc; outline-offset: 3px; }
@media (max-width: 480px) { .pay-btn { display: flex; } }
</style>A small card for a single product with what is included and a reassurance line under the button.
<div class="price-card">
<h3>Starter kit</h3>
<p class="price">$49 <small>one-off</small></p>
<ul><li>12 page templates</li><li>Free updates</li><li>Commercial licence</li></ul>
<a href="https://buy.stripe.com/your-link-id">Get the kit</a>
<p class="note">Secure checkout by Stripe. Instant download.</p>
</div>
<style>
.price-card { max-width: 280px; padding: 20px; border: 1px solid #e5e7eb; border-radius: 16px; font: 15px system-ui, sans-serif; }
.price-card h3 { margin: 0; }
.price { font-size: 32px; font-weight: 700; margin: 6px 0; }
.price small { font-size: 14px; color: #6b7280; font-weight: 400; }
.price-card ul { padding-left: 18px; color: #374151; }
.price-card a { display: block; text-align: center; padding: 12px; border-radius: 10px; background: #111827; color: #fff; text-decoration: none; font-weight: 600; }
.note { font-size: 12px; color: #6b7280; text-align: center; }
</style>Use a quieter style for a second price, such as a yearly plan beside a monthly one.
<a class="pay-outline" href="https://buy.stripe.com/your-yearly-link">Pay yearly, save 2 months</a>
<style>
.pay-outline { display: inline-block; padding: 12px 22px; border: 2px solid #111827; border-radius: 10px;
color: #111827; font: 600 16px system-ui, sans-serif; text-decoration: none; }
.pay-outline:hover { background: #111827; color: #fff; }
</style>Create the Buy Button from the payment link's page in the Dashboard, then paste the code it gives you. It has this shape.
The script loads once per page; each stripe-buy-button tag draws one button. The IDs come from your Dashboard.
<script async src="https://js.stripe.com/v3/buy-button.js"></script>
<stripe-buy-button
buy-button-id="buy_btn_XXXXXXXXXXXX"
publishable-key="pk_live_XXXXXXXXXXXX"
></stripe-buy-button>Load the script once, then render the custom element. In TypeScript you may need to declare the element in a .d.ts file.
import { useEffect } from "react";
export function StripeBuyButton({ buttonId, publishableKey }) {
useEffect(() => {
if (document.querySelector('script[src*="buy-button.js"]')) return;
const s = document.createElement("script");
s.src = "https://js.stripe.com/v3/buy-button.js";
s.async = true;
document.body.appendChild(s);
}, []);
return <stripe-buy-button buy-button-id={buttonId} publishable-key={publishableKey} />;
}Add these to the end of the link as a query string. Values must be URL-encoded.
| Parameter | Example | What it does |
|---|---|---|
| prefilled_email | ?prefilled_email=ana%40example.com | Fills in the email field |
| prefilled_promo_code | ?prefilled_promo_code=LAUNCH20 | Applies a promotion code (promotion codes must be on) |
| client_reference_id | ?client_reference_id=order_1042 | Stores your own reference on the checkout session |
| locale | ?locale=fr | Shows checkout in a given language |
| utm_source, utm_medium, utm_campaign, utm_term, utm_content | ?utm_source=newsletter&utm_campaign=autumn | Records the campaign that sent the buyer |
Copies UTM tags from the page URL onto every payment link on the page, so the sale is credited to the ad or post that brought the visitor.
const tags = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
const page = new URLSearchParams(location.search);
document.querySelectorAll('a[href^="https://buy.stripe.com/"]').forEach((a) => {
const url = new URL(a.href);
tags.forEach((t) => { if (page.get(t)) url.searchParams.set(t, page.get(t)); });
a.href = url.toString();
});Set the after-payment redirect to a URL like https://yoursite.com/thanks?session_id={CHECKOUT_SESSION_ID}. The page can show a friendly message straight away and, if you have a server, confirm the payment.
Plain HTML that works anywhere. Keep the real delivery (download link, account access) behind a server check or a webhook.
<main class="thanks">
<h1>Thank you, your payment went through</h1>
<p>A receipt is on its way to your inbox. Your order reference is <strong id="ref">being confirmed</strong>.</p>
<a href="/start-here">Start here</a>
</main>
<script>
const id = new URLSearchParams(location.search).get("session_id");
if (id) document.getElementById("ref").textContent = id.slice(-8).toUpperCase();
</script>Uses Stripe's official Node library. Never trust the URL alone; ask Stripe whether the session was paid.
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export async function verify(sessionId) {
const session = await stripe.checkout.sessions.retrieve(sessionId);
return session.payment_status === "paid"
? { ok: true, email: session.customer_details?.email }
: { ok: false };
}
Start in test mode so nothing real is charged. Create the product first, because the link is built from a product and price. Add a clear name and a square image; both appear on the checkout page.
When creating the link, decide what to collect: billing address, shipping address, phone number or custom fields such as a company name. Every extra field costs some completed payments, so ask only for what you need to fulfil the order.
If you sell to places that charge sales tax or VAT, turn on automatic tax collection, which uses Stripe Tax and needs your tax registrations set up. Otherwise add tax into your price and say so on the page.
The simplest route is a normal link styled as a button, which loads instantly and matches your design. The examples below give three styles to copy. The Buy Button is the second route: Stripe draws the button for you inside your page and handles the click.
Open the link in the same tab. Opening checkout in a new tab confuses people on phones and breaks the return to your thank-you page.
Stripe does not charge for the link itself. You pay Stripe's normal processing fee on each successful payment, which depends on your country and the payment method. Use the payment processing fee calculator to see what a sale nets you.
Yes. Give the product a recurring price, such as monthly or yearly, and the link starts a subscription. Customers can then manage it through Stripe's customer portal if you turn that on.
In the payment link's after-payment settings, choose not to show Stripe's confirmation page and enter your page URL. You can include {CHECKOUT_SESSION_ID} in the URL, and Stripe replaces it with the session ID so your page or server can look up the order.
Not on its own. Anyone with the URL can open a thank-you page. For downloads or account access, deliver through something Stripe confirms, such as a webhook on your server, an automation that reacts to the payment, or a delivery platform connected to Stripe.
Yes. Stripe documents utm_source, utm_medium, utm_campaign, utm_term and utm_content as link parameters, and client_reference_id for your own reference. Add them to the link behind each ad or post.
Related: Payment processing fee calculator, How to sell digital products, UTM builder, How to create a pricing page, CSS button generator.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.