Checkout for buyers
The buyer pays on RekberPay, never to you. You ask for a checkout link for one milestone and send the buyer there. The buyer does not need to sign in.
1. Ask for a checkout link
DEAL_ID and MS_ID are the deal and milestone ids from Create a deal.
CHECKOUT_URL=$(curl -s -X POST "https://api.rekberpay.com/v1/enterprise/platform/deals/$DEAL_ID/milestones/$MS_ID/checkout" \
-H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" | jq -r .data.url)The full answer:
201 Created
{
"success": true,
"data": {
"url": "https://rekberpay.com/checkout/p/rpt.eyJwIjoiY2hlY2tvdXQiLCJ4IjoxfQ.q3J8vYc0bX2mN5tK9wE1rL7sA4dF6hG8jZ0pQ2uV4yI",
"expires_at": "2026-10-21T08:30:00.000Z"
}
}- The milestone must be
awaiting_payment(else409 INVALID_STATE), and the buyer must still be linked to you (else409 USER_NOT_AVAILABLE). - Needs the
ordersscope. - Ask for a new link whenever the buyer is ready to pay. Each call returns a new link; older links keep working until they expire or the milestone is paid.
2. Send the buyer to the link
Redirect the buyer, or show the link as a button. Open it in the buyer's browser, not in a frame inside your app.
The page shows your name, the order and milestone titles, the amount, the buyer's fee share and the total. The buyer picks a payment method (bank transfer, virtual account, QRIS or another enabled method) and pays. The payment method fee is added on top and is paid by the buyer.
| What the buyer pays | Field on the milestone |
|---|---|
| The milestone price | amount |
| Plus the buyer's share of the RekberPay fee | buyer_fee |
| Equals | funding_amount |
| Plus the payment method fee, shown at checkout | not stored on the milestone |
How long a link lives
- A checkout link is valid for 30 minutes and opens only that one payment.
- It starts one payment. Once the buyer has chosen a method and a payment was created, the link can still show the payment status, but a second payment answers
409 CHECKOUT_USED. Ask for a new link if the buyer wants another method. - One payment per milestone at a time. While an earlier payment on the milestone can still be paid (a gateway charge before its expiry, or a manual transfer the buyer said they sent), a new link cannot start another one: the page answers
409 PAYMENT_IN_PROGRESSand the buyer finishes the first payment, or tries again after it expires. So a buyer can never pay one milestone twice. - Limits for accounts without KYC. A milestone counts toward the buyer's and the seller's non-KYC limits from checkout or payment, not when you create the deal. Making the link answers
422 LIMIT_EXCEEDED(withpartyandreason) when either person has no room left for it, and the buyer page checks again when the buyer pays. - If the order changed after you made the link (another amount, the buyer unlinked, the order cancelled), the page shows
409 CHECKOUT_CHANGED. Make a new link. - An expired or broken link shows "link expired" (
410 LINK_EXPIRED).
The link is a bearer secret: anyone with it can pay that milestone, but it can never be used as an API credential. Do not log it or put it in analytics.
After a gateway payment: the return page
A gateway (for example an e-wallet) sends the buyer back to RekberPay at https://rekberpay.com/checkout/p/r/<payment_link_id>. That page reads the payment status without the checkout token, so it works even when the payment settles after the 30 minutes are over. It is kept for 30 days and shows only your name, the amount and the status, no personal data.
There is no redirect back to your site. Follow the order with webhooks or by reading the deal (next section), and show your own "payment received" screen when the milestone is paid.
Know when the buyer has paid
| Milestone status | Meaning | Event |
|---|---|---|
awaiting_payment | Nothing paid yet | |
paid | RekberPay holds the money. Ask the seller to ship | milestone.paid |
cancelled | You cancelled the order, or this milestone, before payment | deal.cancelled when the whole deal ends cancelled |
Listen for milestone.paid, or read GET /v1/enterprise/platform/deals/:id and check the milestone status and paid_at. Do not ship on the buyer's word or on the return page alone.
A gateway confirms by itself. A manual bank transfer or manual QRIS is checked by RekberPay staff after the buyer presses Saya sudah bayar, so it can take longer. The milestone stays awaiting_payment until then.
While a payment can still land, the deal or the milestone cannot be cancelled (409 PAYMENT_IN_PROGRESS).
In the sandbox
A sandbox order never reaches a gateway. The checkout page shows Simulasikan pembayaran, which marks the milestone paid with test money. Your server can do the same with the checkout token, the part of the URL after /checkout/p/:
CHECKOUT_TOKEN=${CHECKOUT_URL##*/checkout/p/}
curl -X POST "https://api.rekberpay.com/v1/platform/checkout/$CHECKOUT_TOKEN/simulate"{ "success": true, "data": { "milestone_status": "paid", "is_test": true } }The simulate call spends the token like a real payment. On a live order it answers 404, and a sandbox order refuses real payment methods (409 TEST_DEAL).
Checklist
- Make the link only when the buyer is about to pay. It lives 30 minutes.
- Treat the link as a secret. Never log it.
- Wait for
milestone.paidbefore you tell the seller to ship. - In live mode, test one real payment of a small order before you open to all users.