File batching
Submit due payments to a partner as a single file, and settle them from the partner's response file.
Some payment partners collect by file rather than by API. They take one file holding every payment for the run, and they answer later with a file of their own. File batching is how your collection module builds that file, sends it, and settles the payments once the partner replies.
Your module owns the file. The platform never reads inside it, so the format is entirely yours. What the platform does is group the due payments, store what you sent, and route the partner's reply back to you.
Choose the submission path
How a due payment reaches a provider depends on the provider type.
| API payment provider | File batching | File-based debit provider | |
|---|---|---|---|
| Config | batching.enabled: true | batching.enabled: true plus fileConfig | batching.enabled: false |
| Who submits | Your module's hook | Your module's hook | The platform batcher |
| What your hook returns | A result per payment | A list of actions | Nothing, you write no hook |
| Who builds the file | No file | Your module | The platform |
| Code you write | A submitPayments hook | A submitPayments hook and a response hook | None |
"File batching" and "file-based debit provider" are not the same thing. A file-based debit
provider is submitted for you by the platform batcher, and you write no code. File batching is for
a partner the platform has no batcher for, so your module builds and sends the file itself.
What file batching covers
File batching only picks up payments created from a scheduled payment. A payment created any
other way, including one created directly through the API, is never added to a batch and never
reaches your submission hook. If your partner needs ad hoc payments in the file, they have to come
from a schedule.
Turn on file batching
Add a fileConfig block inside batching in your .root-config.json. It is only valid when
batching.enabled is true.
{
"settings": {
"billingSettings": {
"batching": {
"enabled": true,
"submitPaymentsFunction": "submitPayments",
"submitBatchSize": 100,
"scheduleTimeUtc": "05:00",
"latestSubmissionTimeUtc": "20:00",
"submissionLeadTime": 2,
"fileConfig": {
"naming": {
"prefix": "ACMEPAY",
"dateToken": "ccyymmdd",
"sequenceSource": "batch_id"
},
"transport": {
"type": "https",
"deliveryMethodRef": "0b1c0d2e-3f40-4a51-8b62-7c83d94e05f6"
},
"handleResponseFunction": "handleResponseFile",
"responseVia": "webhook"
}
}
}
}
}See Configure file batching for every field, its default, and what the platform checks when you
publish.
How a batch moves
-
The platform collects your module's due payments on an hourly tick, inside the window set by
scheduleTimeUtcandlatestSubmissionTimeUtc, and splits them into batches ofsubmitBatchSize. -
The platform calls your submission hook once per batch, with every payment in that batch.
-
Your hook builds the file and sends it to the partner over HTTPS.
-
Your hook returns a list of actions describing what it sent.
move_to_outboxis the one that matters: it carries the file content and the reference you wrote into the file for each payment. -
The platform stores the file, stamps those references onto the payments, records the batch as delivered, and reports every payment in it as submitted.
-
The partner replies, either in the response to your own delivery request or by posting a file to the platform.
responseViasays which. -
The platform calls your response hook with the reply, the batch's payments, and the references you wrote for them. You return one
update_paymentfor each payment the reply resolves.
Steps 3 and 7 are the code you write. The rest is the platform, including the guard that stops the same batch being sent to a partner twice.
Actions your module returns
Your submission hook returns an array of actions instead of { results: [...] }.
| Action | Return it when | What the platform does |
|---|---|---|
move_to_outbox | The partner has the file | Stores the file, stamps a provider_reference on each payment, and marks the batch delivered |
move_to_archive | After the file is delivered | Copies the file into a dated archive folder |
move_to_inbox | The partner replied in your delivery response | Stores the reply and queues it for your response hook |
update_payment_batch | You want to move the batch | Sets the batch to submitted, accepted, failed or archived |
release_batch_for_retry | Your request never left your module | Returns the batch to pending so it is submitted again |
update_payment | From your response hook only | Settles one payment from the partner's reply |
Prevent double collection
Only return
move_to_outboxwhen the partner has the file. The platform treats it as proof of
delivery and reports every payment in the batch as submitted.
Only return
release_batch_for_retrywhen you can prove the request never left your module, which
means a refused connection, a DNS failure, or a TLS failure before the request was written. A
timeout, a connection dropped mid-request, or any status code at all means the partner may hold
the file. Return neither action in those cases. Retrying a file the partner already has debits
every payment in it twice.
A partner that rejects the file is a failure, not a retry. Report it with update_payment_batch and a failed status, with no move_to_outbox, and the payments settle under the reason you gave.
Give every payment a reference in move_to_outbox. That reference is the only thing tying a line in the partner's reply back to a payment on the platform, so a batch missing one cannot be settled from the reply at all.
Where the platform stores your files
The platform keeps three folders for your module. You cannot configure them, and your partner never sees them, because delivery is your module's own HTTPS request rather than a read from a bucket.
| Folder | Holds |
|---|---|
| Outbox | The file your module reported sending. Kept for the life of the batch. |
| Archive | A copy of the delivered file, in a folder dated by the day it went out. |
| Inbox | Every raw reply from the partner, as it arrived, stamped with the time of receipt. |
Batch statuses
| Status | Description |
|---|---|
pending | The batch is built and nothing has been sent. |
submitting | A run is in progress and the file may be on its way to the partner. |
submitted | Your module reported the file as sent. |
accepted | The partner confirmed it received the file. |
failed | The batch ended without being collected. Final. |
archived | The batch is finished. Final. |
Your module moves a batch with update_payment_batch. It can set submitted, accepted, failed or archived. The other two belong to the platform.
A batch left in
submittingmeans a run may have had the file on its way to the partner when
something broke. The platform cannot tell an unsent file from an unacknowledged one, so it stops
and raises an alarm instead of guessing. Somebody has to confirm what the partner holds before
that batch moves again.
Next step
Configure file batching to set up fileConfig field by field.
In this section
- Configure file batching covers every field in
batchingandfileConfig, and what the platform checks when you publish. - Build and submit the batch file is the detail behind steps 3 and 4, including every action and how to report a request that failed.
- Handle response files is step 7, both reply routes, and the endpoint your partner posts to.
- Batch states and file storage has the full status flow and the fields the platform records on a batch.
- File batching example is a working module you can read end to end.
- Instructions for your payment partner is one page to hand your partner.
Updated 15 days ago