Run a deal in Sandbox, then in Live
A deal is a contract split into milestones. Each milestone is funded, delivered, approved and released on its own. This guide follows one milestone from the first click to a settled payout, using the dashboard and the API side by side. Run it in Sandbox first. The last section lists what is different in Live.
If you want the same flow as one API script with every real response, read the Enterprise quickstart and Milestone deal end to end.
The path of one milestone
| Status | What it means | Who moves it |
|---|---|---|
draft | The deal is still being edited | Operator |
awaiting_funding | The deal is active and waits for the payer's money | Finance |
funded | The money is held. Work can start | Operator delivers the milestone |
evidence_submitted | Approvers are reviewing the evidence | Finance approvers |
revision_requested | An approver sent it back with a note | Operator delivers again |
approved | Every needed approval is in | Finance releases |
released | Money is on its way to the payout accounts | RekberPay settles |
disputed | RekberPay is reviewing a dispute | RekberPay decides |
cancelled | Closed without payout |
A deal is completed when every milestone that is not cancelled is released.
1. Add the counterparty and a payout account
Do this once per company you pay.
In the dashboard
- Counterparties, New counterparty: company name, country code, relationship, optional contact.
- Payouts, Instructions tab, New payout instruction: a label, the counterparty, bank, account number, account holder, country code and currency. In Sandbox the instruction is verified at once. In Live it waits in
pending_reviewuntil RekberPay verifies it, so add it early. See Approve, release and settle.
With the API
curl -X POST https://api.rekberpay.com/v1/enterprise/payout-instructions \
-H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" \
-H "Content-Type: application/json" \
-d '{
"label": "Mitra Pangan main account",
"counterparty_id": "'"$COUNTERPARTY_ID"'",
"currency": "IDR",
"bank_name": "BCA",
"account_number": "8001234567",
"account_holder": "CV Mitra Pangan Nusantara",
"country_code": "ID"
}'If the counterparty has its own Enterprise workspace, also link it now.
2. Create the deal
You need the operator role or above.
In the dashboard
- Deals, then New deal.
- Under Terms, choose the counterparty (or choose later), give a Title, an optional description, an optional external reference such as a PO number, and say whether the deal is within Indonesia or cross-border.
- Under Milestones, add each one with a title and an amount. You can add Required evidence (what the payer expects to see) and a due date. Use a template to start from a saved plan.
- Under Platform fee, choose who pays the fee. See Agree who pays the fee.
- Choose Create deal. It is saved as a draft with a reference like
DEAL-2026-0001.
A deal holds 1 to 20 milestones. Each amount is from Rp 10.000 to Rp 50.000.000.000. The API also accepts USD, SGD, MYR and EUR deals through currency; the dashboard creates rupiah deals.
With the API
curl -X POST https://api.rekberpay.com/v1/enterprise/deals \
-H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" \
-H "Content-Type: application/json" \
-d '{
"title": "Packaging order, Q4",
"description": "Printed cartons, 20.000 units, delivered to Cikarang",
"external_ref": "PO-7781",
"counterparty_id": "'"$COUNTERPARTY_ID"'",
"milestones": [
{ "title": "Deposit", "amount": 30000000, "required_evidence": "Signed order confirmation" },
{ "title": "Production proof", "amount": 40000000, "required_evidence": "Proof sheet" },
{ "title": "Delivery", "amount": 30000000, "required_evidence": "Delivery note" }
]
}'While the deal is a draft you can still change it: Edit deal, New milestone, and Edit on a milestone, or PATCH /v1/enterprise/deals/:id, POST /v1/enterprise/deals/:id/milestones and PATCH /v1/enterprise/deals/:id/milestones/:mid. Anything else answers 409 NOT_DRAFT.
3. Activate
Activation freezes the terms, including the fee split, and makes every milestone awaiting_funding.
In the dashboard, choose Activate on the deal and confirm.
With the API
curl -X POST https://api.rekberpay.com/v1/enterprise/deals/$DEAL_ID/activate \
-H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY"Activation refuses when:
- no counterparty is set:
409 COUNTERPARTY_REQUIRED - the linked partner has not agreed the fee split yet:
409 FEE_NOT_AGREED - the deal has no milestones:
409 NO_MILESTONES
To drop a deal, choose Cancel deal (POST /v1/enterprise/deals/:id/cancel). Before any money moved it is cancelled at once. Once money is held, finance cancels alone when the counterparty has not joined with a workspace, and proposes a cancellation when it has: the counterparty confirms or declines within 7 days, and each cancelled milestone is refunded with its fee share. See Cancelling a deal. A payment still in progress blocks it (409 PAYMENT_IN_PROGRESS).
4. Fund the first milestone (sandbox)
In Sandbox you record the funding yourself. You need the finance role.
In the dashboard, on the milestone row choose Record funding, then Record funding again in the dialog. The method and reference are for your own records. The dialog reminds you that no money moves.
With the API
curl -X POST https://api.rekberpay.com/v1/enterprise/deals/$DEAL_ID/milestones/$MILESTONE_ID/fund \
-H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" \
-H "Content-Type: application/json" \
-d '{ "method": "sandbox", "reference": "TEST-001" }'The milestone becomes funded. A deal made in the dashboard is paid upfront by default: for that, fund every milestone at once with POST /v1/enterprise/deals/$DEAL_ID/fund (Fund with test money on the deal card), and the milestone call answers 409 FUND_WHOLE_DEAL until then. A deal made with a workspace key is paid per milestone unless the create call sends funding_mode: "upfront". This call works only in Sandbox. In Live it answers 409 LIVE_FUNDING_IS_PLATFORM_CONFIRMED: live money is paid and confirmed as described in Fund a live deal.
5. Deliver the milestone
An operator delivers the milestone once it is funded.
In the dashboard, choose Deliver milestone on the milestone. Describe what the delivery shows (10 to 500 characters), tick documents already on the deal or upload new ones (PDF, JPG, PNG or WebP up to 10 MB), then submit.
With the API
curl -X POST https://api.rekberpay.com/v1/enterprise/deals/$DEAL_ID/milestones/$MILESTONE_ID/submit-evidence \
-H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" \
-H "Content-Type: application/json" \
-d '{
"evidence_summary": "Signed order confirmation PO-7781 attached.",
"document_ids": []
}'Register supporting files first with POST /v1/enterprise/documents, then pass their ids in document_ids (up to 10).
When the counterparty is linked, the partner delivers from its own Shared deals page and the payer's team approves. When it is not linked, the payer's team records the delivery on the partner's behalf.
The milestone becomes evidence_submitted. The approvers are notified. The evidence is now locked: it cannot be deleted while it is under review, in a dispute, approved or released.
6. Approve
An approver with the finance role or above decides. Not the person who delivered the milestone.
In the dashboard, open Approvals, open the milestone and choose Approve, Reject or Request revision. Reject and Request revision need a note of at least 5 characters, and both send the milestone back to revision_requested so the milestone can be delivered again.
A milestone at or above the workspace's four-eyes threshold needs two different approvers. The default threshold is Rp 100.000.000 and an admin changes it in Settings, Approval policy. See Four-eyes approvals.
With the API
curl -X POST https://api.rekberpay.com/v1/enterprise/approvals/$MILESTONE_ID/decide \
-H "Authorization: Bearer $REKBERPAY_APPROVER_KEY" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" \
-H "Content-Type: application/json" \
-d '{ "decision": "approved", "note": "Matches the order confirmation." }'decision is approved, rejected or revision_requested. The answer shows approvals_done and approvals_required. A decision is final once saved.
7. Release
When the milestone is approved, a finance member releases it to one to five verified payout accounts.
In the dashboard, choose Release on the milestone (or Release now right after approving). In Pay to, pick the accounts and amounts. The amounts must add up to the payout, which is the milestone amount minus the counterparty's fee share.
With the API
curl -X POST https://api.rekberpay.com/v1/enterprise/deals/$DEAL_ID/milestones/$MILESTONE_ID/release \
-H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" \
-H "Content-Type: application/json" \
-d '{
"splits": [
{ "payout_instruction_id": "'"$INSTRUCTION_ID"'", "amount": 30000000 }
]
}'Release is final. In Sandbox the payout is settled on the spot as test data. Details are in Approve, release and settle.
8. Repeat, then close
Repeat steps 4 to 7 for the next milestones. When the last one is released the deal is completed. On a completed deal Share summary copies a plain text summary. Use Activity or GET /v1/enterprise/events to follow what happened, and the audit export (GET /v1/enterprise/audit/export.csv, finance) for your files.
If something goes wrong on a funded milestone, open a dispute. See Disputes on a workspace deal.
Going live
Live opens when RekberPay approves your business verification. Choose Live on the switch next to the workspace name (an API call uses a rpe_live_ key). Then:
- Your Sandbox stays. Nothing is cancelled or removed. Test deals keep their Test deal label, live on in Sandbox and can never release real money. Switch back to Sandbox whenever you want to test something.
- Live starts empty. Create live deals in Live. A deal made in Sandbox is test data forever.
- Add live payout instructions early. They wait for RekberPay's verification (
pending_review). - Funding is paid, not recorded. Record funding becomes Pay. The payer chooses bank transfer, QRIS or a gateway, and RekberPay confirms the money. See Fund a live deal.
- Payouts are real. A release queues a payout that RekberPay operations send to the bank and mark settled. You are notified when it settles or fails.
- A live deal needs a partner with Live unlocked. Creating or activating a live deal with a linked partner whose Live is still locked answers
409 COUNTERPARTY_LIVE_LOCKED. A partner acts on a live deal from its own Live. - Counterparties must be verified to be paid. A live release to a counterparty that has not completed business verification waits, and the money stays held. A live, verified RekberPay workspace passes. See Verify a counterparty.
- Refunds are real. If RekberPay cancels a funded milestone in a dispute, the payer is refunded by bank transfer. In Sandbox the refund is marked sent at once as test data. See Refunds when a dispute cancels a milestone.
- Keys and webhooks are per mode. Make a
rpe_live_key and a Live webhook endpoint. Live endpoints get only live events (livemode: true), and Sandbox endpoints only test events.
A quick comparison:
| Sandbox | Live | |
|---|---|---|
| Funding | Record funding, no money | Pay by bank transfer, QRIS or gateway, confirmed by RekberPay |
| Payout instructions | Verified at once | pending_review until RekberPay verifies |
| Release | Payout settles at once as test data | Payout is queued, then settled by RekberPay. Needs a verified counterparty |
| Dispute refund | Marked sent at once as test data | Queued, then sent by RekberPay operations, with a notice when it is sent |
| Deals | Test deals | Real deals |
| API keys | rpe_test_, 10 active per mode | rpe_live_, 10 active per mode |
| Emails | Members only, tagged [Sandbox] | Members and counterparties |