Skip to content

Webhooks

RekberPay POSTs JSON to your configured webhook URL when escrow state changes. This page documents every event, the signature scheme, and the retry policy.

For the integration walkthrough (verify, handle retries, idempotency), see Handling webhooks.

Delivery

  • Method: POST
  • Content-Type: application/json
  • From IPs: Documented at https://api.rekberpay.com/.well-known/webhook-ips (allowlist these in your firewall)
  • Timeout: 5 seconds — return 2xx within that window
  • Retries: Up to 7 attempts on non-2xx (see retry table)

Signature

Every webhook includes a signature field — HMAC-SHA256 of the canonical event string, hex-encoded.

Canonical string:

event + escrow_id + amount + status + timestamp

Verify with:

js
import crypto from 'node:crypto';

function verify(body, secret) {
    const canonical = `${body.event}${body.escrow_id}${body.amount}${body.status}${body.timestamp}`;
    const expected = crypto.createHmac('sha256', secret).update(canonical).digest('hex');
    return crypto.timingSafeEqual(
        Buffer.from(body.signature, 'hex'),
        Buffer.from(expected, 'hex'),
    );
}

See Authentication for the HMAC scheme. Same algorithm as link signing, different secret.

Common envelope

Every webhook has these fields:

FieldTypeDescription
eventstringEvent name (see below)
escrow_idUUIDThe escrow this event is about
refstringYour ref from when you signed the link
amountintegerIDR, no decimals
statusstringThe escrow's state after this event
timestampISO 8601When the event occurred (UTC)
dataobjectEvent-specific extra fields
signaturehex stringHMAC-SHA256 verification signature

Events

escrow.created

Fired immediately after a partner-signed escrow is created.

FieldTypeDescription
data.expires_atISO 8601When the escrow auto-cancels if unpaid
data.escrow_urlURLBuyer payment link
json
{
    "event": "escrow.created",
    "escrow_id": "7f8a9b0c-1d2e-3f4a-5b6c-7d8e9f0a1b2c",
    "ref": "MARKETPLACE_98765",
    "amount": 22500000,
    "status": "pending_payment",
    "timestamp": "2026-05-18T07:00:00.000Z",
    "data": {
        "expires_at": "2026-05-25T07:00:00.000Z",
        "escrow_url": "https://rekberpay.com/escrow/7f8a.../pay"
    },
    "signature": "..."
}

payment.completed

Buyer paid, funds in escrow.

FieldTypeDescription
data.payment_methodstringqris, bank_transfer, gopay, shopeepay, crypto
data.paid_atISO 8601When the gateway confirmed
data.feeintegerPlatform fee withheld on release
json
{
    "event": "payment.completed",
    "escrow_id": "7f8a...",
    "ref": "MARKETPLACE_98765",
    "amount": 22500000,
    "status": "paid",
    "timestamp": "2026-05-18T09:27:00.000Z",
    "data": {
        "payment_method": "qris",
        "paid_at": "2026-05-18T09:26:55.000Z",
        "fee": 5000
    },
    "signature": "..."
}

escrow.sent

Seller marked the goods/service delivered.

FieldTypeDescription
data.tracking_numberstring | nullIf the seller provided one
data.courierstring | nullCourier name (e.g., JNE, J&T)
data.delivered_atISO 8601Server-side timestamp

escrow.received

Buyer confirmed receipt.

json
{
    "event": "escrow.received",
    "escrow_id": "7f8a...",
    "ref": "MARKETPLACE_98765",
    "amount": 22500000,
    "status": "received",
    "timestamp": "2026-05-19T14:00:00.000Z",
    "data": {
        "confirmed_at": "2026-05-19T14:00:00.000Z"
    },
    "signature": "..."
}

escrow.released

Funds released to seller balance. Terminal state.

FieldTypeDescription
data.released_bystringbuyer, auto_release, or admin
data.release_methodstringmanual or sla_timeout
data.seller_payoutintegerAmount credited to seller's RekberPay balance

escrow.refunded

Funds refunded to buyer. Terminal state.

FieldTypeDescription
data.refunded_bystringadmin or auto_refund
data.refund_reasonstringFree-form note

escrow.disputed

Buyer or seller opened a dispute.

FieldTypeDescription
data.opened_bystringbuyer or seller
data.reasonstringnot_as_described, not_received, damaged, fraud, other
data.descriptionstringFree-form text from the disputer

dispute.resolved

Admin resolved a dispute.

FieldTypeDescription
data.outcomestringreleased, refunded, or hold
data.resolution_notestringAdmin's note

status reflects the new escrow state (released, refunded, or hold).

What status looks like

The status field is the escrow's state after the event:

EventResulting status
escrow.createdpending_payment
payment.completedpaid
escrow.sentsent
escrow.receivedreceived
escrow.releasedreleased
escrow.refundedrefunded
escrow.disputeddisputed
dispute.resolvedreleased, refunded, or hold

Subscribing to events

By default, you receive all events. To filter, email [email protected] with the events you want.

We don't currently support per-escrow event subscriptions — partner-level only.

Replaying

Failed deliveries can be replayed from the partner dashboard at https://dashboard.rekberpay.com/webhooks/<event-id>/replay. Replays carry the same event_id so your idempotency key works.

See also

Released under the proprietary RekberPay license. Built for Indonesian merchants.