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.
The Postman collection has every request in this guide, ready to run, if you would rather not type them yourself.
Step 1: Create the payment link
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.
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.
Step 2: Send the shopper to the link
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.
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.
Step 4: Handle an unpaid link
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 becomesPAIDonly when one charge reachesSUCCEEDED. To see why an attempt failed, list the link’s charges withGET /api/v1/charges?source_in=PAYMENT_LINK&sourceId={paymentLinkId}and read thefailureCode. See charge failure codes. - The shopper never paid. The link becomes
EXPIREDonceexpiresAtpasses. - 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.