Payments & Fund Transfers

Payment Webhooks

Example webhook bodies for payments, batch payments, maker-checker approvals and refunds.

See how to read the webhook examples. The values are made up, but every field, its order and its format match what Acme sends.

Payments

Successful payment (payments.succeeded):

{
  "id": "wbh_0RWF7FTX5Y711",
  "createdAt": "2026-10-08T02:11:46.917522108Z",
  "mode": "LIVE",
  "event": "payments.succeeded",
  "object": {
    "id": "pymt_0RWF7FTTNY6RR",
    "type": "FAST",
    "amount": 245000,
    "currency": "SGD",
    "customerReference": "INV-2026-10-0412",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "receiver": {
      "name": "TAN WEI MING",
      "bank": "OCBCSGSGXXX",
      "bankAccountNumber": "5012846731"
    },
    "paymentDetails": "Invoice 0412 payment",
    "currencyExchange": {
      "fxContractId": null
    },
    "senderAccountCurrency": "SGD",
    "status": "COMPLETED",
    "resultCode": null,
    "bankReference": null,
    "bankReferences": {},
    "createdAt": "2026-10-08T02:11:40.318Z",
    "updatedAt": "2026-10-08T02:11:46.902Z"
  }
}

These fields are left out when they have no value:

  • In receiver: any field without a value, such as bank and bankAccountNumber for a proxy payment, or proxyType and proxyValue for an account payment
  • bankChargeBearer, instructionForSenderBank, underlyingErrorMessage and paymentAdviceEmails
  • batchId and paymentDate, for a payment that is not part of a batch
  • actualPaymentDate, bankChargeAmount and bankChargeCurrency, which are sent for a payment in a batch once the bank reports them
  • review, which is sent only with the four maker-checker events

Other details you sent when you created the payment, such as purposeCode, are also returned as extra fields in the payment and in receiver.

bankReference and bankReferences are filled only when the bank returns a reference. The keys in bankReferences are the bank's own field names.

Failed payment (payments.failed):

{
  "id": "wbh_0RWF7FV9NY7AF",
  "createdAt": "2026-10-08T02:12:05.115370442Z",
  "mode": "LIVE",
  "event": "payments.failed",
  "object": {
    "id": "pymt_0RWF7FV9DY443",
    "type": "FAST",
    "amount": 245000,
    "currency": "SGD",
    "customerReference": "INV-2026-10-0413",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "receiver": {
      "name": "TAN WEI MING",
      "bank": "OCBCSGSGXXX",
      "bankAccountNumber": "5012846739"
    },
    "paymentDetails": "Invoice 0413 payment",
    "currencyExchange": {
      "fxContractId": null
    },
    "senderAccountCurrency": "SGD",
    "status": "FAILED",
    "resultCode": "INVALID_ACCOUNT",
    "underlyingErrorMessage": "1010 Payer/payee account is incorrect",
    "bankReference": null,
    "bankReferences": {},
    "createdAt": "2026-10-08T02:11:58.404Z",
    "updatedAt": "2026-10-08T02:12:05.101Z"
  }
}

Payments in a batch

Payments in a batch are sent with payments.succeeded or payments.failed:

  • They are sent when Acme processes the bank's acknowledgement file, with several payments under objects.
  • One webhook carries up to 100 payments. A larger batch is split across several webhooks.
  • The bank can confirm some payments before others. Each webhook then carries the payments confirmed so far, and the rest arrive in later webhooks.
  • A webhook can also carry a single payment under object. Accept both object and objects.
  • Process each payment on its own, by its id. Do not rely on its position in the array.
{
  "id": "wbh_0RWF7FVA9Y6FQ",
  "createdAt": "2026-10-09T01:12:44.873519027Z",
  "mode": "LIVE",
  "event": "payments.succeeded",
  "objects": [
    {
      "id": "pymt_0RWF7FVA5Y52Q",
      "type": "GIRO",
      "amount": 420000,
      "currency": "SGD",
      "customerReference": "SAL-OCT26-0001",
      "senderAccountId": "intacc_0QK7M2D4XH1PZ",
      "receiver": {
        "name": "TAN WEI MING",
        "bank": "OCBCSGSGXXX",
        "bankAccountNumber": "5012846731"
      },
      "batchId": "bpmt_0QK7N8V2FB3RT",
      "paymentDate": "2026-10-09",
      "paymentDetails": "Salary Oct 2026",
      "currencyExchange": {
        "fxContractId": null
      },
      "senderAccountCurrency": "SGD",
      "status": "COMPLETED",
      "resultCode": null,
      "bankReference": null,
      "bankReferences": {},
      "createdAt": "2026-10-08T09:02:11.481Z",
      "updatedAt": "2026-10-09T01:12:44.861Z"
    },
    {
      "id": "pymt_0RWF7FVA5Y52S",
      "type": "GIRO",
      "amount": 385000,
      "currency": "SGD",
      "customerReference": "SAL-OCT26-0002",
      "senderAccountId": "intacc_0QK7M2D4XH1PZ",
      "receiver": {
        "name": "NUR AISYAH BINTE RAHMAN",
        "bank": "UOVBSGSGXXX",
        "bankAccountNumber": "3609127745"
      },
      "batchId": "bpmt_0QK7N8V2FB3RT",
      "paymentDate": "2026-10-09",
      "paymentDetails": "Salary Oct 2026",
      "currencyExchange": {
        "fxContractId": null
      },
      "senderAccountCurrency": "SGD",
      "status": "COMPLETED",
      "resultCode": null,
      "bankReference": null,
      "bankReferences": {},
      "createdAt": "2026-10-08T09:02:11.481Z",
      "updatedAt": "2026-10-09T01:12:44.861Z"
    }
  ]
}

Maker-checker flow

Payment waiting for approval (payments.pending-approval):

{
  "id": "wbh_0RWF7FVB1Y5CA",
  "createdAt": "2026-10-08T03:41:28.376879315Z",
  "mode": "LIVE",
  "event": "payments.pending-approval",
  "object": {
    "id": "pymt_0RWF7FVAXY5ZZ",
    "type": "FAST",
    "amount": 1100000,
    "currency": "SGD",
    "customerReference": "INV-2026-0429",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "receiver": {
      "name": "SUNRISE LOGISTICS PTE LTD",
      "bank": "DBSSSGSGXXX",
      "bankAccountNumber": "0039182746"
    },
    "paymentDetails": "Invoice 0429 payment",
    "currencyExchange": {
      "fxContractId": null
    },
    "senderAccountCurrency": "SGD",
    "status": "PENDING_APPROVAL",
    "resultCode": null,
    "bankReference": null,
    "bankReferences": {},
    "createdAt": "2026-10-08T03:41:26.929Z",
    "updatedAt": "2026-10-08T03:41:26.929Z",
    "review": {
      "requestedBy": "ak_finance_maker",
      "approvedAt": null,
      "approvedBy": null,
      "rejectedAt": null,
      "rejectedBy": null,
      "rejectionReason": null,
      "expiresAt": "2026-10-09T03:41:26.929745Z"
    }
  }
}

Payment approved (payments.approved). It carries the payment as it stands after Acme submits it to the bank:

  • status is usually PROCESSING. A payments.succeeded or payments.failed webhook follows when the bank settles the payment.
  • When the bank answers at once, status can already be COMPLETED or FAILED. The payments.succeeded or payments.failed webhook can then arrive before this one.
  • When Acme could not submit the payment, status can still be PENDING_APPROVAL.
{
  "id": "wbh_0RWF7FVBNY6D4",
  "createdAt": "2026-10-08T04:12:55.110044791Z",
  "mode": "LIVE",
  "event": "payments.approved",
  "object": {
    "id": "pymt_0RWF7FVAXY5ZZ",
    "type": "FAST",
    "amount": 1100000,
    "currency": "SGD",
    "customerReference": "INV-2026-0429",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "receiver": {
      "name": "SUNRISE LOGISTICS PTE LTD",
      "bank": "DBSSSGSGXXX",
      "bankAccountNumber": "0039182746"
    },
    "paymentDetails": "Invoice 0429 payment",
    "currencyExchange": {
      "fxContractId": null
    },
    "senderAccountCurrency": "SGD",
    "status": "PROCESSING",
    "resultCode": null,
    "bankReference": null,
    "bankReferences": {},
    "createdAt": "2026-10-08T03:41:26.929Z",
    "updatedAt": "2026-10-08T04:12:55.004Z",
    "review": {
      "requestedBy": "ak_finance_maker",
      "approvedAt": "2026-10-08T04:12:54.882011Z",
      "approvedBy": "Jane Lim",
      "rejectedAt": null,
      "rejectedBy": null,
      "rejectionReason": null,
      "expiresAt": "2026-10-09T03:41:26.929745Z"
    }
  }
}

Approval rejected (payments.approval-rejected):

{
  "id": "wbh_0RWF7FVBSY56Q",
  "createdAt": "2026-10-08T04:30:12.554302178Z",
  "mode": "LIVE",
  "event": "payments.approval-rejected",
  "object": {
    "id": "pymt_0RWF7FVAXY5ZZ",
    "type": "FAST",
    "amount": 1100000,
    "currency": "SGD",
    "customerReference": "INV-2026-0429",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "receiver": {
      "name": "SUNRISE LOGISTICS PTE LTD",
      "bank": "DBSSSGSGXXX",
      "bankAccountNumber": "0039182746"
    },
    "paymentDetails": "Invoice 0429 payment",
    "currencyExchange": {
      "fxContractId": null
    },
    "senderAccountCurrency": "SGD",
    "status": "APPROVAL_REJECTED",
    "resultCode": null,
    "bankReference": null,
    "bankReferences": {},
    "createdAt": "2026-10-08T03:41:26.929Z",
    "updatedAt": "2026-10-08T04:30:12.231Z",
    "review": {
      "requestedBy": "ak_finance_maker",
      "approvedAt": null,
      "approvedBy": null,
      "rejectedAt": "2026-10-08T04:30:12.231019Z",
      "rejectedBy": "Jane Lim",
      "rejectionReason": "Beneficiary not on approved vendor list",
      "expiresAt": "2026-10-09T03:41:26.929745Z"
    }
  }
}

Approval expired (payments.approval-expired):

{
  "id": "wbh_0RWF7FVBXY6F9",
  "createdAt": "2026-10-09T03:41:30.001284507Z",
  "mode": "LIVE",
  "event": "payments.approval-expired",
  "object": {
    "id": "pymt_0RWF7FVAXY5ZZ",
    "type": "FAST",
    "amount": 1100000,
    "currency": "SGD",
    "customerReference": "INV-2026-0429",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "receiver": {
      "name": "SUNRISE LOGISTICS PTE LTD",
      "bank": "DBSSSGSGXXX",
      "bankAccountNumber": "0039182746"
    },
    "paymentDetails": "Invoice 0429 payment",
    "currencyExchange": {
      "fxContractId": null
    },
    "senderAccountCurrency": "SGD",
    "status": "APPROVAL_EXPIRED",
    "resultCode": null,
    "bankReference": null,
    "bankReferences": {},
    "createdAt": "2026-10-08T03:41:26.929Z",
    "updatedAt": "2026-10-09T03:41:30.001Z",
    "review": {
      "requestedBy": "ak_finance_maker",
      "approvedAt": null,
      "approvedBy": null,
      "rejectedAt": null,
      "rejectedBy": null,
      "rejectionReason": null,
      "expiresAt": "2026-10-09T03:41:26.929745Z"
    }
  }
}

In review, requestedBy, approvedBy and rejectedBy say who took that step:

  • For an API key, its name, or its ID when the key has no name.
  • For a dashboard user, their name, or their email until they have set a name.

Batch Payments

Batch payment submitted (payment-batches.submitted):

{
  "id": "wbh_0RWF7FVP1Y763",
  "createdAt": "2026-10-08T09:05:37.218394502Z",
  "mode": "LIVE",
  "event": "payment-batches.submitted",
  "object": {
    "id": "bpmt_0QK7N8V2FB3RT",
    "type": "GIRO",
    "paymentDate": "2026-10-09",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "senderAccountCurrency": "SGD",
    "currency": "SGD",
    "status": "SUBMITTED",
    "metadata": {
      "fileName": "UFF1_ROCKETSG01_20261008_0905.txt"
    },
    "createdAt": "2026-10-08T09:02:11.481Z",
    "updatedAt": "2026-10-08T09:05:37.206Z"
  }
}

Batch payment rejected (payment-batches.rejected). underlyingErrorMessage is the bank's reason:

{
  "id": "wbh_0RWF7FVPSY5H8",
  "createdAt": "2026-10-08T09:21:03.790126518Z",
  "mode": "LIVE",
  "event": "payment-batches.rejected",
  "object": {
    "id": "bpmt_0QK7N8V2FB3RT",
    "type": "GIRO",
    "paymentDate": "2026-10-09",
    "senderAccountId": "intacc_0QK7M2D4XH1PZ",
    "senderAccountCurrency": "SGD",
    "currency": "SGD",
    "status": "FAILED",
    "underlyingErrorMessage": "ACK2007 Duplicate BatchId",
    "metadata": {
      "fileName": "UFF1_ROCKETSG01_20261008_0905.txt"
    },
    "createdAt": "2026-10-08T09:02:11.481Z",
    "updatedAt": "2026-10-08T09:21:03.774Z"
  }
}

Refunds

Successful refund (refunds.succeeded):

{
  "id": "wbh_0RWF7FVRSY4SH",
  "createdAt": "2026-10-08T09:50:25.426288002Z",
  "mode": "LIVE",
  "event": "refunds.succeeded",
  "object": {
    "id": "rfnd_0RWF7FVRHY6GG",
    "transactionId": "txn_0QK6ZB1R4T8WM",
    "amount": 1240,
    "currency": "SGD",
    "status": "SUCCEEDED",
    "resultCode": null,
    "createdAt": "2026-10-08T09:50:20.414Z",
    "updatedAt": "2026-10-08T09:50:25.421Z"
  }
}

Failed refund (refunds.failed):

{
  "id": "wbh_0RWF7FVSNY74X",
  "createdAt": "2026-10-08T09:50:58.068242142Z",
  "mode": "LIVE",
  "event": "refunds.failed",
  "object": {
    "id": "rfnd_0RWF7FVSDY7D4",
    "transactionId": "txn_0QK6ZC7X2N5DE",
    "amount": 15000,
    "currency": "SGD",
    "status": "FAILED",
    "resultCode": "REQUESTED_REFUND_AMOUNT_EXCEEDS_REFUNDABLE_AMOUNT",
    "createdAt": "2026-10-08T09:50:53.053Z",
    "updatedAt": "2026-10-08T09:50:58.059Z"
  }
}

On this page