Skip to content

Approve, release and settle ​

Once a milestone is delivered, three things stand between the money and the counterparty: an approval, a release and a settlement. They are separate on purpose. The person who approves is not the person who delivered the milestone, and the bank account that receives the money is one RekberPay already verified and signed.

1. Approve ​

An approver is anyone with the finance role or above, except the person who delivered the milestone.

In the dashboard

  1. Open Approvals. The Pending tab lists milestones waiting for a decision. A badge on the menu counts them.
  2. Open one. Read the delivery summary, the documents and the requirements.
  3. Choose Approve, Reject or Request revision. Reject and Request revision need a note of at least 5 characters, which the person who delivered will read.

Approving records your decision. It does not move money. Reject and Request revision both send the milestone back to revision_requested, close the round, and let the milestone be delivered again, which starts a new round.

With the API

bash
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.

Four-eyes ​

A milestone with an amount at or above the workspace's four-eyes threshold needs two approvals from two different people. Below it, one is enough. The default threshold is Rp 100.000.000.

An admin changes it in Settings, Approval policy, Four-eyes threshold (IDR). The same card sets the Dispute SLA (hours).

bash
curl -X PATCH https://api.rekberpay.com/v1/enterprise/settings \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "X-Enterprise-Account: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{ "four_eyes_threshold": 50000000 }'

Settings are changed from a dashboard session. A workspace API key can read them but never change them.

RuleError
Only finance, admin and owner can decide403 FORBIDDEN
The person who delivered the milestone cannot decide409 SUBMITTER_CANNOT_APPROVE
One decision per person per round409 ALREADY_DECIDED
The milestone must be waiting for a decision409 NOT_AWAITING_APPROVAL

Because a workspace API key acts as the admin who created it, a key and that admin count as the same person. Give each approver their own login. The full walkthrough is in Four-eyes approvals.

When a milestone belongs to a deal with a linked partner, the partner delivers the milestone from its own workspace. Nobody in the payer's workspace is the submitter, so any eligible approver there can decide.

2. Keep verified payout instructions ​

A payout instruction is a bank destination for money you release. Releases go only to instructions that RekberPay has verified.

In the dashboard

  1. Open Payouts and the Instructions tab.
  2. Choose New payout instruction.
  3. Fill in Label, Counterparty, Bank, Account number, Account holder, Country code and Currency. Leave the counterparty empty to make the account usable for any deal of your workspace.
  4. Save. A live instruction shows pending_review until RekberPay verifies it. A sandbox instruction is verified at once.

With the API

bash
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"
  }'

Account numbers are never returned in full. Answers carry account_number_masked and signed: true instead.

StatusMeaning
pending_reviewWaiting for RekberPay to verify it. Cannot receive a release yet
verifiedCan receive a release
suspendedRekberPay suspended it. Contact RekberPay. It cannot be edited

Changing the bank, account number, holder, country, currency or counterparty of an instruction signs it again and sends it back to pending_review. Renaming the label changes nothing else. Those bank detail changes are refused while a payout to the instruction is queued or processing (409 IN_USE), and an instruction that has ever received a payout cannot be deleted.

How instructions are signed ​

When an instruction is created or changed, RekberPay signs it with HMAC-SHA256. The signature covers these eight fields: account_holder, account_id, account_number, bank_name, counterparty_id, country_code, currency and id. The signing key stays on RekberPay's servers.

Every release, and every retry of a failed payout, checks the signature again. If anyone changed the stored bank details outside the normal flow, the check fails and the release is refused with 409 PAYOUT_INSTRUCTION_TAMPERED. If you ever see that code, stop and contact RekberPay.

Including counterparty_id is what keeps a counterparty's account from being turned into a workspace-wide one behind your back. Instructions signed with the older format, which did not cover the counterparty, are accepted during a short transition while RekberPay re-signs them. You do not need to do anything.

3. Release ​

When the milestone is approved, a finance member releases it. A release pays one to five accounts.

In the dashboard

  1. On the deal, choose Release on the milestone. If you just approved it, you can choose Release now.
  2. In Pay to (up to 5 accounts), pick verified accounts and give each an amount. The total must equal the payout amount shown. The dialog tells you how much is left to allocate.
  3. Confirm. Release is final.

The payout amount is the milestone amount minus the partner's share of the platform fee. If the payer pays the whole fee, it equals the milestone amount.

A live release waits for the counterparty's business verification. You can fund and approve a milestone while the counterparty is unverified. The money stays held, Release is off with the note Waits for KYB, and the approval page says the payout waits. The deal shows a banner with Send verification link. Release opens once RekberPay approves the counterparty, or when the counterparty is a live, verified RekberPay workspace. Sandbox deals are not affected. See Verify a counterparty.

With the API

bash
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": "'"$MAIN_ACCOUNT_ID"'", "amount": 20000000 },
      { "payout_instruction_id": "'"$FREIGHT_ACCOUNT_ID"'", "amount": 9760000 }
    ]
  }'

200 OK

json
{
    "success": true,
    "data": {
        "milestone_id": "fffffff4-ffff-4fff-8fff-ffffffffffff",
        "status": "released",
        "deal_status": "in_progress",
        "seller_fee": 240000,
        "payout_amount": 29760000,
        "disbursements": [
            {
                "id": "55555551-5555-4555-8555-555555555551",
                "payout_instruction_id": "44444441-4444-4444-8444-444444444441",
                "amount": 20000000,
                "currency": "IDR",
                "status": "queued"
            },
            {
                "id": "55555552-5555-4555-8555-555555555552",
                "payout_instruction_id": "44444442-4444-4444-8444-444444444442",
                "amount": 9760000,
                "currency": "IDR",
                "status": "queued"
            }
        ]
    }
}
StatusCodeCause
400SPLITS_MISMATCHThe splits do not add up to the payout amount
400INSTRUCTION_NOT_ELIGIBLEAn instruction is not verified, not in the deal currency, or belongs to another counterparty
409PAYEE_CHOSE_PAYOUTThe counterparty chose where it is paid. Release without splits
409NOT_APPROVEDThe milestone is not approved, for example a four-eyes milestone with one approval
409TEST_DEALA test deal cannot release real money
409LIVE_DEAL_IN_SANDBOXA live deal cannot release from Sandbox, and a live milestone funded with sandbox money never releases real payouts. Switch to Live
409COUNTERPARTY_KYB_REQUIREDThe counterparty has not completed business verification. Nothing is paid out and the money stays held. The error carries kyb_status and a verify_path
409PAYOUT_INSTRUCTION_TAMPEREDAn instruction failed its signature check. Contact RekberPay
403FORBIDDENYour role is below finance

Each account can appear once in a release. Releasing with split payouts shows a full run with real answers.

Release to the counterparty's chosen account ​

On a deal shared with a counterparty workspace, the counterparty can choose where it is paid (Share a deal with your counterparty). When it did, the deal shows payee_payout_chosen: true and you release with no splits: the whole payout goes to that account as one payout, and you never see its details. Send {} as the body. Sending splits anyway answers 409 PAYEE_CHOSE_PAYOUT.

bash
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 '{}'

The chosen account is checked again at release: it must still be verified, in the deal mode and currency, at least 24 hours past its verification, and held in the name of the counterparty. If it no longer passes, release asks for your own splits as usual (400 INVALID_BODY when you send none). Nothing is paid to a stale choice.

4. Settlement ​

Each split becomes one disbursement. It moves through these statuses:

StatusMeaning
queuedReleased and waiting for RekberPay operations
processingRekberPay is sending it to the bank
settledThe money reached the account. settled_at is set and a bank reference is recorded
failedIt did not go through. failure_reason says why

In Sandbox every payout is settled immediately as test data and never reaches operations.

In Live RekberPay operations send the transfer and mark it settled. You are notified when a payout settles or fails. A failed payout stays failed until RekberPay queues it again, to the same account or to another verified instruction. The milestone stays released throughout, and your team does not need to release it again.

In the dashboard, open Payouts. The Queue tab lists every payout with its status, a status filter, and a summary of today's payouts, the amount still queued and the average settlement time. The deal page shows each milestone's payouts too.

With the API

bash
curl "https://api.rekberpay.com/v1/enterprise/payouts?status=queued" \
  -H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY"

Webhooks and the activity feed carry disbursement.queued, disbursement.processing, disbursement.settled, disbursement.failed and disbursement.requeued. Finance can export every payout as CSV with GET /v1/enterprise/reports/disbursements.csv.

Next steps ​

Escrow, payment services and B2B deals for Indonesian businesses.