Skip to Content
Payment LinksIntegration Guide

Integration Guide

This guide walks through a first payment with the Payment Links API, from creating the link to knowing that the payment succeeded.

Follow it against the Playground environment first. Playground accepts the same calls as production but does not move real money, and the Test Data page has cards that produce each outcome.

Before you start, you need:

  • Your Playground merchant ID and API key. See Authentication.
  • A webhook endpoint that Beam can reach over HTTPS. See the Webhook guide.
Tip

The Postman collection has every request in this guide, ready to run, if you would rather not type them yourself.

Call POST /api/v1/payment-links from your backend with the order and the payment methods you want to offer. Prices are in the smallest currency unit, so 1000000 means 10,000.00 THB.

The linkSettings object controls which payment methods appear on the checkout page; see Payment methods on a payment link for each group. The example below offers cards, card installments, eWallets, mobile banking, and QR PromptPay.

POST https://playground.api.beamcheckout.com/api/v1/payment-links Content-Type: application/json Authorization: Basic <base64(merchantId:apiKey)> { "order": { "currency": "THB", "description": "Pets Shop", "netAmount": 100, "referenceId": "order#10001", "orderItems": [ { "itemName": "American shorthair", "description": "Cat", "price": 1000000, "quantity": 2, "sku": "S", "productId": "automated_01" }, { "itemName": "Chihuahua", "description": "Dog", "price": 1000000, "quantity": 1, "sku": "XS", "productId": "automated_02" } ] }, "linkSettings": { "card": { "isEnabled": true }, "cardInstallments": { "isEnabled": true, "installments3m": { "isEnabled": true }, "installments4m": { "isEnabled": true }, "installments6m": { "isEnabled": true }, "installments10m": { "isEnabled": true } }, "qrPromptPay": { "isEnabled": true }, "eWallets": { "isEnabled": true }, "mobileBanking": { "isEnabled": true }, "buyNowPayLater": { "isEnabled": false } }, "collectDeliveryAddress": false, "redirectUrl": "https://www.beamcheckout.com", "expiresAt": "2026-06-05T04:20:04.067Z" }

Beam replies with the link’s id and its url:

{ "id": "rGtqz6DafS", "url": "https://playground-pay.beamcheckout.com/merchantId/rGtqz6DafS" }

Store the id against your order. You need it to look the link up later, and it is also the sourceId you use to find the link’s charges.

Tip

Send an idempotency key with this call. If your request times out and you retry, the key stops Beam creating a second link for the same order.

For every field, including cancelUrl, collectPhoneNumber, and feeType, see Optional features and CreatePaymentLinkRequest.

Redirect the shopper to the url from the response, or send it to them however you normally reach them: email, chat, or a QR code on a printed invoice. They complete the payment on Beam’s hosted checkout page, so there is nothing to build here.

If you set a redirectUrl, the shopper returns to it after paying. If you set a cancelUrl, the page also shows a cancel button that returns them to you. See Cancellation for the two ways to handle that.

Note

Do not render the payment link inside an iframe . Beam attaches the X-Frame-Options: DENY header for security, so it will not load. See the MDN reference .

Step 3: Wait for the result

Beam sends a webhook when the link is paid. Subscribe to payment_link.paid, and fulfill the order when it arrives. This is the reliable signal: it reaches your backend even if the shopper closes their browser right after paying, which the redirectUrl does not.

Your endpoint should verify the signature, respond with HTTP 2xx quickly, and do the slow work afterwards. See Authenticating Webhooks and Event Types for the payloads.

If you cannot receive webhooks yet, poll the link instead:

GET https://playground.api.beamcheckout.com/api/v1/payment-links/{paymentLinkId} Authorization: Basic <base64(merchantId:apiKey)>

The response is the full payment link, with its current status:

{ "paymentLinkId": "rGtqz6DafS", "merchantId": "merchantId", "url": "https://playground-pay.beamcheckout.com/merchantId/rGtqz6DafS", "status": "ACTIVE", "order": { "netAmount": 100, "currency": "THB", "description": "Pets Shop", "referenceId": "order#10001" }, "collectDeliveryAddress": false, "redirectUrl": "https://www.beamcheckout.com", "expiresAt": "2026-06-05T11:20:04.067+07:00", "feeType": "TRANSACTION_FEE" }

Keep polling until status is no longer ACTIVE. A shopper who never pays leaves the link ACTIVE until it expires, so use polling only until your webhook endpoint is ready, and move to webhooks before you go live. For what each status means, see the payment link lifecycle.

Poll with exponential backoff and jitter, because polling too fast gets 429 responses. See Rate limits and retries.

A payment link is single use, and a shopper can fail to pay it in more than one way.

  • The shopper’s payment was declined. The link stays ACTIVE, so they can try again. Each attempt creates its own charge, and the link becomes PAID only when one charge reaches SUCCEEDED. To see why an attempt failed, list the link’s charges with GET /api/v1/charges?source_in=PAYMENT_LINK&sourceId={paymentLinkId} and read the failureCode. See charge failure codes.
  • The shopper never paid. The link becomes EXPIRED once expiresAt passes.
  • You want to stop it being paid. Disable the link. This works only while it is ACTIVE:
PATCH https://playground.api.beamcheckout.com/api/v1/payment-links/{paymentLinkId}/disable Authorization: Basic <base64(merchantId:apiKey)>

A link cannot be edited, deleted, or re-enabled. To offer the shopper another attempt after disabling or expiry, create a new link.

Next steps

  • Payment Links: the optional features, the lifecycle, and the cancellation flows.
  • Charges: the payment attempts behind each link.
  • Refunds: reverse a paid link.
  • Go-live Checklist: what to confirm before you switch to production.
Last updated on