Checkout

Hosted checkout link

A single-use URL to the full-page checkout, minted server-side. Good for emails, marketing pages, server-side redirects, or anywhere the embed script can't run.

Buy link (no server code)

The fastest way to sell: paste a permanent product URL anywhere (email, landing page, social) and each click mints a fresh checkout. No API key, no server. The URL is:

https://pay.meridapay.com/pay/<product-id>

Get it pre-filled from the dashboard: open the product, click Sell this product → Link tab → Copy. Optional query passthroughs:

discount_codestring

Pre-applied discount, same code your dashboard issued.

success_urlhttps URL

Override where the buyer lands after paying. {CHECKOUT_TOKEN} in the URL is substituted with the actual session token.

Under the hood, the buyer worker calls POST /buy-links/<id>/checkout on the API surface to mint the session. You don't need to think about it unless you want server-side control (next section).

Mint a link from your backend

When you need to attach per-buyer context (customer email, your own user id external_customer_id, metadata that should ride on every webhook, an idempotency key), call POST /checkouts from your backend instead. The response includes a pay.meridapay.com/<token> URL.

typescript
// Your backend (example: Next.js route handler)
export async function POST() {
  const res = await fetch("https://api.meridapay.com/checkouts", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MERIDA_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      product_id: "<product-id>",
      customer_email: "[email protected]",
      external_customer_id: "user_123",
      success_url: "https://app.example.com/thanks",
    }),
  })
  const { url } = await res.json()
  return Response.redirect(url, 303)
}

See API reference for the full request/response shape.

Prefill via query params

If you know the buyer's identity (logged-in user, known lead), pass it in the body of POST /checkouts (preferred, see the snippet above) so it rides on every webhook. For lightweight one-off prefills, you can also append query params to the minted URL before redirecting:

https://pay.meridapay.com/<token>[email protected]&name=Jane%20Doe&discount_code=LAUNCH20
emailstring

Prefill the buyer's email input.

namestring

Prefill the cardholder name input.

discount_codestring

Pre-applied discount code.

brandhex color

Pay button tint. Hex only. Anything else is ignored.

labelstring

Display title shown in place of the product name, up to 140 characters. Handy when many checkouts ride one shared product and each needs its own title. Display only, so reporting keeps the product's real name.

Query-param prefills are visible to anyone who sees the URL. Treat them as public.

Idempotency

Pass an Idempotency-Key header on POST /checkouts so retries from your backend (timeouts, redeliveries) return the same checkout instead of minting duplicates.

Currency

A product can be priced in more than one currency. When a buyer opens the hosted checkout, MeridaPay selects the currency that matches their region automatically. If your product offers that currency, the buyer sees the local price right away. If not, the checkout falls back to the product's default currency.

The buyer can switch among the currencies your product offers at any time before paying. The charge always uses the currency shown when they confirm.

To pin one currency for all buyers regardless of location, pass currency in the body of POST /checkouts:

typescript
body: JSON.stringify({
  product_id: "<product-id>",
  customer_email: "[email protected]",
  currency: "EUR",           // always charge in EUR
  success_url: "https://app.example.com/thanks",
}),

If you omit currency, the checkout handles selection for you.

After the payment

The buyer pays on pay.meridapay.com/<token> and is redirected to your success_url with ?status=paid&payment_link_id=<token> appended. The authoritative confirmation comes from the payment.succeeded webhook, not from the buyer landing on that URL (they might close the tab).