1. Global Account
PIK
  • Start
    • Getting Started
  • Authentication
    • Authentication Token
      POST
  • Global Account
    • Contacts
      • Create Contact
      • List Contacts
      • Get Contact
      • Count Contacts
    • Virtual Accounts
      • Create Virtual Account
      • List Virtual Accounts
      • Get Virtual Account
    • Transactions
      • List Transactions
      • Get Transaction
    • Account Balance
      • List Account Balances
      • Get Balance by Currency
    • Payout
      • Create Payout
    • Webhooks
      • Unified Webhook Entry
      • Virtual Account Webhook
      • Deposit Webhook
      • Payout Status Webhook
  • Payment Links
    • Payment Links
      • Create Payment Link
      • Update Payment Link
      • Get Payment Link Detail
      • Get Payment Link List
    • Transactions
      • Get Transaction List
  • Webhook
    • Global Account
      • Deposit Webhook
      • Payout Webhook
      • Virtual Account Webhook
    • Payment Links
      • Overview
      • Order Collect Out Webhook
      • Customer Payment Webhook
      • Customer Refund Webhook
      • Master Recharge Webhook
      • Web3 Direct Payment Webhook
      • Withdraw Out Webhook
  1. Global Account

Payout Webhook

PIK pushes a webhook to your endpoint whenever a payout (outgoing transfer) you initiated changes state. Use these events to track the lifecycle of each payout — from upstream pickup to settlement or failure — and to keep your own ledger and notifications in sync.
This document covers everything needed to integrate the Payout webhook end-to-end: delivery format, signature verification, retry behaviour, the full set of event types, the state machine, and a JSON sample for every event.

1. How delivery works#

ItemValue
HTTP methodPOST
Content typeapplication/json; charset=utf-8
Request timeout10 seconds
Success ruleHTTP 2xx is treated as ack; anything else is a failure
Retry policyUp to 5 retries, 5 minutes between attempts

Required headers#

HeaderDescription
Content-TypeAlways application/json.
X-Webhook-EventEvent group. For this document the value is always PAYOUT.
X-Webhook-Event-TypeConcrete event type (see §3 Event types).
X-Webhook-SignatureHex-encoded HMAC-SHA256 of the raw request body using your App Secret. Present only when an App Secret is configured for your account.

Signature verification#

The signature is computed as:
X-Webhook-Signature = HEX( HMAC_SHA256( app_secret, raw_request_body ) )
Sign the raw request body bytes (UTF-8), not a re-serialized JSON, and verify in constant time.
Node.js example
Python example

Client response requirements#

Reply with HTTP 200 (or any 2xx) as soon as you have persisted the event.
Any non-2xx response, network error, or timeout will be retried.
Keep ack bodies small (e.g. {"received":true}) — we only log the first 1000 chars of the response.

Retry behaviour#

AttemptTrigger
1Immediately when PIK processes the source event
2–65 minutes after the previous failure
FinalAfter 5 retries the task is marked EXHAUSTED and is not sent again

Idempotency#

Webhooks may be delivered more than once (retries, network blips, replays). Use event_id as the idempotency key in your handler — if you have already processed an event_id, return 2xx and skip the side-effect.
For business identity across events for the same payout, use data.payout_id (stable across ready.send, completed, failed, compliance.rejected).

2. Envelope#

Every Payout webhook shares the same outer envelope:
{
  "version": "V1.6.0",
  "event_name": "PAYOUT",
  "event_type": "payout.ready.send | payout.completed | payout.failed | payout.compliance.rejected",
  "event_id": "<uuid, unique per event delivery>",
  "source_id": "<payout_id this event refers to>",
  "data": { ... }
}
FieldTypeDescription
versionstringWebhook payload schema version.
event_namestringEvent group. Always PAYOUT.
event_typestringConcrete event. See §3.
event_idstringUnique ID of this event delivery. Use as idempotency key.
source_idstringThe business object the event is about. For payouts this is payout_id.
dataobjectEvent-specific payload. See §4.

3. Event types#

event_typeMeaningTerminal?
payout.ready.sendThe payout has been accepted and is being dispatched. Funds are committed but not yet settled.No
payout.completedPayout has settled. The beneficiary has received funds and the fee is final.Yes
payout.failedPayout failed (e.g. beneficiary bank rejection). No funds were debited.Yes
payout.compliance.rejectedPayout was rejected by compliance. No funds were debited.Yes

4. State machine#

   Payout created via API
   (local status = INIT, funds reserved)
              │
              ▼
   ┌────────────────────────────┐
   │  payout.ready.send         │   payout has been picked up for dispatch
   │  (local status = PROCESSING) │
   └──────────────┬─────────────┘
                  │
       ┌──────────┴──────────────────────────────┐
       ▼                                          ▼
 ┌─────────────────────┐         ┌──────────────────────────────────────────┐
 │ payout.completed    │         │ payout.failed                            │
 │ (status = SUCCESS)  │         │   or payout.compliance.rejected          │
 │ Funds debited.      │         │ (status = FAILED)                        │
 │ Fee finalized.      │         │ Reserved funds released. No debit.       │
 └─────────────────────┘         └──────────────────────────────────────────┘
       (terminal)                              (terminal)

How funds and fees are settled#

The payout amount you submitted (e.g. 100) is the gross amount. The fee is deducted from this amount, not on top of it.
Example: gross = 100, fee = 8 → beneficiary receives 92, your account is debited exactly 100.
On payout.ready.send, funds are still reserved (no balance write).
On payout.completed, the reservation is released and the gross amount is debited from your balance in a single move. A separate fee transaction is recorded for visibility but does not debit additional funds.
On payout.failed / payout.compliance.rejected, the reservation is released; no debit, no fee transaction.

5. data field reference#

FieldTypeAlways present?Description
payout_idstringyesUnique payout identifier. Stable across all events for this payout. Use to dedupe by payout.
account_idstringyesThe sub-account from which the payout is funded.
statusstringyesPayout status string, e.g. Pending, Completed, Failed, Rejected.
currencystringyesISO 4217 currency code of the payout amount.
amountstringyesGross payout amount as a decimal string.
fee_amountstringyesFinal fee deducted from amount, as a decimal string. Final value is on payout.completed.
fee_currencystringyesCurrency of fee_amount.
beneficiary_idstringoptionalBeneficiary the payout is sent to.
referencestringoptionalReference string supplied at payout creation.
fail_reasonstringoptionalPresent on payout.failed / payout.compliance.rejected. Human-readable failure message.
create_timestringyesISO-8601 timestamp when the payout was created.
complete_timestringoptionalISO-8601 timestamp when the payout settled. null until terminal Completed.
update_timestringyesISO-8601 timestamp of the latest status update.
All monetary fields are sent as strings to avoid floating-point precision loss. Parse them with a decimal type (BigDecimal, decimal.Decimal, etc.).

6. Sample payloads#

6.1 payout.ready.send#

{
  "version": "V1.6.0",
  "event_name": "PAYOUT",
  "event_type": "payout.ready.send",
  "event_id": "b2cf6e21-2a90-4d68-a4d7-6c9a44210cd1",
  "source_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
  "data": {
    "payout_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
    "account_id": "ac1e31ab-f0fd-4432-91fb-b06ec1b3d7b9",
    "beneficiary_id": "be8a17d0-7e8d-4f4a-9b81-1bd5e7b9aa11",
    "status": "Pending",
    "currency": "USD",
    "amount": "100.00",
    "fee_currency": "USD",
    "fee_amount": "0",
    "reference": "INV-20260525-001",
    "create_time": "2026-05-25T15:00:00+08:00",
    "update_time": "2026-05-25T15:01:30+08:00",
    "complete_time": null
  }
}

6.2 payout.completed#

{
  "version": "V1.6.0",
  "event_name": "PAYOUT",
  "event_type": "payout.completed",
  "event_id": "8e3f9bc4-2dcb-4ef9-9d33-a7d04b7c2cf8",
  "source_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
  "data": {
    "payout_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
    "account_id": "ac1e31ab-f0fd-4432-91fb-b06ec1b3d7b9",
    "beneficiary_id": "be8a17d0-7e8d-4f4a-9b81-1bd5e7b9aa11",
    "status": "Completed",
    "currency": "USD",
    "amount": "100.00",
    "fee_currency": "USD",
    "fee_amount": "5.00",
    "reference": "INV-20260525-001",
    "create_time": "2026-05-25T15:00:00+08:00",
    "complete_time": "2026-05-25T15:12:44+08:00",
    "update_time": "2026-05-25T15:12:44+08:00"
  }
}

6.3 payout.failed#

{
  "version": "V1.6.0",
  "event_name": "PAYOUT",
  "event_type": "payout.failed",
  "event_id": "fc1c8d4e-d3bd-44a6-a4e0-5a98c3bf21d7",
  "source_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
  "data": {
    "payout_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
    "account_id": "ac1e31ab-f0fd-4432-91fb-b06ec1b3d7b9",
    "beneficiary_id": "be8a17d0-7e8d-4f4a-9b81-1bd5e7b9aa11",
    "status": "Failed",
    "currency": "USD",
    "amount": "100.00",
    "fee_currency": "USD",
    "fee_amount": "0",
    "reference": "INV-20260525-001",
    "fail_reason": "Beneficiary bank rejected the transfer",
    "create_time": "2026-05-25T15:00:00+08:00",
    "complete_time": null,
    "update_time": "2026-05-25T15:18:02+08:00"
  }
}

6.4 payout.compliance.rejected#

{
  "version": "V1.6.0",
  "event_name": "PAYOUT",
  "event_type": "payout.compliance.rejected",
  "event_id": "27b5b1c4-1ed1-4f37-a3ed-8d23ec8b9f01",
  "source_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
  "data": {
    "payout_id": "7c1d9f1b-9b6e-4a3b-bbf5-3a2f4f4d9e21",
    "account_id": "ac1e31ab-f0fd-4432-91fb-b06ec1b3d7b9",
    "beneficiary_id": "be8a17d0-7e8d-4f4a-9b81-1bd5e7b9aa11",
    "status": "Rejected",
    "currency": "USD",
    "amount": "100.00",
    "fee_currency": "USD",
    "fee_amount": "0",
    "reference": "INV-20260525-001",
    "fail_reason": "Compliance rejected",
    "create_time": "2026-05-25T15:00:00+08:00",
    "complete_time": null,
    "update_time": "2026-05-25T15:05:11+08:00"
  }
}

Modified at 2026-05-25 08:15:10
Previous
Deposit Webhook
Next
Virtual Account Webhook
Built with