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

Deposit Webhook

PIK pushes a webhook to your endpoint whenever a deposit (incoming fund) on one of your virtual accounts changes state. Use these events to keep your own ledger in sync with PIK and to notify your end users when funds arrive.
This document covers everything needed to integrate the Deposit 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#

Every request carries the following HTTP headers:
HeaderDescription
Content-TypeAlways application/json.
X-Webhook-EventEvent group. For this document the value is always DEPOSIT.
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. Long-running work should be done asynchronously.
Any non-2xx response, network error, or timeout will be retried.
Responses are read but truncated to the first 1000 chars in our log — keep ack bodies small (e.g. {"received":true}).

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
A delivery is considered a success on the first 2xx and is not retried further.

Idempotency#

Webhooks may be delivered more than once (retries, network issues, 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 deposit, use data.deposit_id (stable across pending, completed, compliance.rejected).

2. Envelope#

Every Deposit webhook shares the same outer envelope:
{
  "version": "V1.6.0",
  "event_name": "DEPOSIT",
  "event_type": "deposit.pending | deposit.completed | deposit.compliance.rejected",
  "event_id": "<uuid, unique per event delivery>",
  "source_id": "<deposit_id this event refers to>",
  "data": { ... }
}
FieldTypeDescription
versionstringWebhook payload schema version.
event_namestringEvent group. Always DEPOSIT.
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 deposits this is deposit_id.
dataobjectEvent-specific payload. See §4.

3. Event types#

event_typeMeaningTerminal?
deposit.pendingFunds have been received and are awaiting compliance review.No
deposit.completedFunds have cleared and have been credited to the account balance.Yes
deposit.compliance.rejectedThe deposit was rejected by compliance and will not be credited.Yes

4. State machine#

                 ┌──────────────────────────────┐
                 │  deposit.pending             │
                 │  (status = "Pending")        │
                 └──────────────┬───────────────┘
                                │
              ┌─────────────────┴──────────────────┐
              ▼                                    ▼
 ┌──────────────────────────┐        ┌────────────────────────────────┐
 │  deposit.completed       │        │  deposit.compliance.rejected   │
 │  (status = "Completed")  │        │  (status = "Rejected")         │
 │  Balance credited        │        │  Funds not credited;           │
 │                          │        │  no balance change             │
 └──────────────────────────┘        └────────────────────────────────┘
        (terminal)                              (terminal)
Notes:
deposit.pending may be skipped for some deposits — you should handle deposit.completed arriving without a prior pending.
deposit.completed is the only event on which we credit the recipient's balance. Treat it as the source of truth for "money has arrived".
The amount and fee on deposit.completed are the final values. Values on deposit.pending are indicative and may change on completion.

5. data field reference#

FieldTypeAlways present?Description
deposit_idstringyesUnique deposit identifier. Stable across all events for this deposit. Use to dedupe by deposit.
account_idstringyesThe virtual account that received the funds.
account_namestringyesThe legal account holder name on the virtual account.
direct_idstringyesParent direct account identifier. "0" if not applicable.
short_reference_idstringyesShort human-readable reference shown to senders.
deposit_currencystringyesISO 4217 currency code of the deposit (e.g. USD).
deposit_amountstringyesGross deposit amount as a decimal string. Use a decimal/BigDecimal type to parse.
deposit_feestringyesFee deducted from deposit_amount (decimal string).
deposit_statusstringyesDeposit status: Pending | Completed | Rejected.
deposit_referencestringoptionalFree-text reference supplied by the sender.
sender_namestringoptionalName of the remitting party, if available.
create_timestringyesISO-8601 timestamp when the deposit was first observed.
complete_timestringoptionalISO-8601 timestamp when the deposit completed. null for rejected deposits.
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 deposit.pending#

{
  "version": "V1.6.0",
  "event_name": "DEPOSIT",
  "event_type": "deposit.pending",
  "event_id": "319318dc-934e-4d96-a994-601383e0d8a6",
  "source_id": "881147e4-89de-4e0e-afbc-7d19f6c4f14b",
  "data": {
    "direct_id": "0",
    "account_id": "ac1e31ab-f0fd-4432-91fb-b06ec1b3d7b9",
    "account_name": "ACME PTE LTD.",
    "deposit_id": "881147e4-89de-4e0e-afbc-7d19f6c4f14b",
    "short_reference_id": "230907-GwisGvJK",
    "deposit_currency": "USD",
    "deposit_amount": "100.00",
    "deposit_fee": "0",
    "deposit_status": "Pending",
    "deposit_reference": "",
    "sender_name": "John Doe",
    "create_time": "2026-05-25T14:19:52+08:00",
    "complete_time": "2026-05-25T14:19:52+08:00",
    "update_time": "2026-05-25T14:19:52+08:00"
  }
}

6.2 deposit.completed#

{
  "version": "V1.6.0",
  "event_name": "DEPOSIT",
  "event_type": "deposit.completed",
  "event_id": "f531776b-df59-4d11-84f0-11e7ae3755f0",
  "source_id": "881147e4-89de-4e0e-afbc-7d19f6c4f14b",
  "data": {
    "direct_id": "0",
    "account_id": "ac1e31ab-f0fd-4432-91fb-b06ec1b3d7b9",
    "account_name": "ACME PTE LTD.",
    "deposit_id": "881147e4-89de-4e0e-afbc-7d19f6c4f14b",
    "short_reference_id": "230907-GwisGvJK",
    "deposit_currency": "USD",
    "deposit_amount": "100.00",
    "deposit_fee": "5.00",
    "deposit_status": "Completed",
    "deposit_reference": "",
    "sender_name": "John Doe",
    "create_time": "2026-05-25T14:19:52+08:00",
    "complete_time": "2026-05-25T14:21:10+08:00",
    "update_time": "2026-05-25T14:21:10+08:00"
  }
}

6.3 deposit.compliance.rejected#

{
  "version": "V1.6.0",
  "event_name": "DEPOSIT",
  "event_type": "deposit.compliance.rejected",
  "event_id": "40f6b64c-e77f-43fb-af12-2cb4b35a8b71",
  "source_id": "881147e4-89de-4e0e-afbc-7d19f6c4f14b",
  "data": {
    "direct_id": "0",
    "account_id": "ac1e31ab-f0fd-4432-91fb-b06ec1b3d7b9",
    "account_name": "ACME PTE LTD.",
    "deposit_id": "881147e4-89de-4e0e-afbc-7d19f6c4f14b",
    "short_reference_id": "230907-GwisGvJK",
    "deposit_currency": "USD",
    "deposit_amount": "100.00",
    "deposit_fee": "0",
    "deposit_status": "Rejected",
    "deposit_reference": "",
    "create_time": "2026-05-25T14:19:52+08:00",
    "complete_time": null,
    "update_time": "2026-05-25T14:25:00+08:00"
  }
}

Modified at 2026-05-25 08:14:42
Previous
Webhook
Next
Payout Webhook
Built with