Skip to main content

Batch Payments

This describes Acme's Batch Payments API. This API can be used to send multiple payments in a single batch to the bank using file transfer.

Which API should I use?

Payments created outside of a Batch (using the Payments API) are sent to the bank over API transport. Payments created within a batch using the Batch Payments API described here are sent to the bank over files (host-to-host integration).

The API you should use to create the payment depends on the integration you have with your bank.

Both kinds of payments are visible in the List Payments API.

Payment Batch API

The Payment Batch API creates a batch of payments all at once. The payments in a batch share a common payment type, payment date, currency, and source account. The payments in a batch will be submitted together in a single file to the bank. Each payment in the batch has its own individual ID that can be used to track its success / failure. The batch itself also has an ID.

Upon receiving the batch, Acme will process and send it to the bank. Any progress reports will be sent via webhook. The changes will also be visible when calling the list or get APIs. A sample timeline of events and webhooks / status changes is provided below.

Create a Batch Payment

POST /v1/payment-batches

{
"type": "MEPS",

// actual payment date may change due to auto value date rollover from bank
// e.g. due to submitting batch after cutoff, or approval taking too long
"paymentDate": "2024-05-10",

"senderAccountId": "intacct_XYZ",

// optional - must be provided if account has multiple currencies configured in Acme
"senderAccountCurrency": "SGD",

"currency": "SGD",
"payments": [
{
"amount": 20000,

// optional - a random string will be generated if not provided
// cannot reuse previous customer references (checked by bank)
"customerReference": "DONUTS",

// optional
"paymentDetails": "10 boxes of 12 each",

// optional - for TT / MEPS: SENDER/RECEIVER/SHARED
"bankChargeBearer": "SENDER",

"receiver": {
"name": "Donut Shop",
"bank": "OCBCSGSGXXX",
"bankAccountNumber": "123456789",

// address must be provided for TT/MEPS
"address": {
"line1": "20 Side Street",
"line2": "Unit 02-3A"
}
}
},
{
"amount": 3000
"customerReference": "COFFEE",
"receiver": {
"name": "Coffee Shop",
"bank": "UOVBSGSGXXX",
"bankAccountNumber": "345678901",
"address": {
"line1": "127 Jln Merdeka"
}
}
},
[...]
]
}

More details on the receiver fields may be found in our Payment documentation.

Response

200 OK

{
"id": "pymtb_XYZ",
"type": "MEPS",
"paymentDate": "2024-05-10",
"senderAccountId": "intacct_XYZ",
"currency": "SGD"
"senderAccountCurrency": "SGD",
"status": "PROCESSING", // PROCESSING (still at Acme) -> SUBMITTED (at the bank) -> FAILED / COMPLETED
"payments": [
{
"id": "pymt_XYZ",
"amount": 20000,
"receiver": { ... },
"status": "PROCESSING" // individual payment status
},
{
"id": "pymt_XYZ",
"amount": 3000,
"receiver": { ... },
"status": "PROCESSING"
},
[...]
]
}

The individual payment objects (pymt_XXX) returned as part of the response are also visible in our Payments API endpoints.

Validation

  • Sender account currency: must be specified if account is configured in Acme as multi-currency
  • Currency
    • MEPS/FAST/PAYNOW: must be SGD
  • Number of payments in one batch: maximum of 1000
  • Receiver name: must be present
  • Receiver address
    • TT/MEPS: must be present
    • ACT: must not be present
    • all except ACT: if present, should fit within 3x35 character lines
  • Receiver bank (for bank account payments - ACT/TT/MEPS/PAYNOW):
    • ACT: must not be present
    • others: must be present

Possible Errors

  • Invalid type for batch
  • Invalid payment date for batch
  • Invalid currency for batch
  • Invalid source account for batch
  • any payment level error e.g. bank account number, bank, account holder name
    • If any payment fails validation by Acme, Acme will currently reject the entire submission. Please resubmit the entire request with the errors corrected.

List Batch Payments

GET /v1/payment-batches

Get a Batch Payment

GET /v1/payment-batches/{id}

Additions to the Payment API

In addition to the existing Payment fields documented on the Payment API documentation, the following fields will be added for Payments which are part of a Payment Batch.

{
"id": "pymt_XYZ",
// ... existing fields ...
"batchId": "pymtb_XYZ",
"paymentDate": "2024-05-10", // as instructed by customer
"actualPaymentDate": "2024-05-12", // if changed by bank
"bankChargeAmount": 100, // if bank charges present (e.g. for TT / MEPS)
"bankChargeCurrency": "SGD"
}

Webhooks

As file-based integration is an inherently asynchronous process, Acme will emit webhooks to inform you of the status of the payments.

  • Payment Batch Submitted (sample) - sent after the file is submitted to the bank
  • Payment Batch Rejected (sample) - sent if the entire batch is rejected
  • Payment Succeeded (sample) - sent for the payments after positive ACK3 (result from clearing system) is received from the bank
  • Payment Failed (sample) - sent for the payments after a rejection at the ACK1 (entire batch), ACK2 (bank validation), or ACK3 (clearing system result) level.

Test mode

You can use your test API key to test your integration before going live. Test mode validates the input parameters and always assumes success, unless one of the special account numbers below are used.

To test failure cases please use the following account numbers (any bank is fine):

  • 000000000 fail this individual payment
  • 000000001 fail this individual payment
  • 000000002 fail the entire batch containing this payment

Test mode will emit the following webhooks for a batch that does not fail entirely:

  • payment-batches.submitted (sample)
  • payments.succeeded and/or payments.failed (sample) for the payments in the batch

If the 000000002 account number is used in a batch, test mode will simulate a failure for the entire batch:

  • payment-batches.submitted (sample)
  • payment-batches.rejected (sample)
  • payments.failed (sample) for all payments in the batch

Sample Timeline

  1. Client submits 10 payments in the batch, 2 of them are obviously invalid e.g. bank code has wrong format (caught by Acme)
  2. Acme returns 400 bad request, no batch object is created.
  3. Client submits 10 payments, fixing the invalid ones.
  4. Acme returns 200 OK, batch object is created (status PROCESSING), payments are created with status PROCESSING
  5. Acme processes the batch and sends a batch of 10 payments to the bank
    1. Batch status change to SUBMITTED, 10 payments status change to SUBMITTED
    2. Acme sends payment batch submitted webhook for the batch
  6. Bank delivers ACK1 accepting the batch
  7. Bank delivers ACK2, 2 of the 10 payments are further rejected
    1. If any of the payments have ACWC (Accepted With Changes) status, Acme will set actualPaymentDate to the changed value
    2. Acme sends payment failed webhook for the 2 payments (payment status change to FAILED)
  8. Bank delivers ACK3, 8 remaining payments are successful
    1. If any of the payments have ACWC (Accepted With Changes) status, Acme will set actualPaymentDate / bankChargeAmount / bankChargeCurrency to the values provided by the bank
    2. Acme sends payment succeeded webhook for the 8 payments (payment status change to COMPLETED)