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 providerFile batchingFile-based debit provider
Configbatching.enabled: truebatching.enabled: true plus fileConfigbatching.enabled: false
Who submitsYour module's hookYour module's hookThe platform batcher
What your hook returnsA result per paymentA list of actionsNothing, you write no hook
Who builds the fileNo fileYour moduleThe platform
Code you writeA submitPayments hookA submitPayments hook and a response hookNone
ℹ️

"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

  1. The platform collects your module's due payments on an hourly tick, inside the window set by scheduleTimeUtc and latestSubmissionTimeUtc, and splits them into batches of submitBatchSize.

  2. The platform calls your submission hook once per batch, with every payment in that batch.

  3. Your hook builds the file and sends it to the partner over HTTPS.

  4. Your hook returns a list of actions describing what it sent. move_to_outbox is the one that matters: it carries the file content and the reference you wrote into the file for each payment.

  5. The platform stores the file, stamps those references onto the payments, records the batch as delivered, and reports every payment in it as submitted.

  6. The partner replies, either in the response to your own delivery request or by posting a file to the platform. responseVia says which.

  7. The platform calls your response hook with the reply, the batch's payments, and the references you wrote for them. You return one update_payment for 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: [...] }.

ActionReturn it whenWhat the platform does
move_to_outboxThe partner has the fileStores the file, stamps a provider_reference on each payment, and marks the batch delivered
move_to_archiveAfter the file is deliveredCopies the file into a dated archive folder
move_to_inboxThe partner replied in your delivery responseStores the reply and queues it for your response hook
update_payment_batchYou want to move the batchSets the batch to submitted, accepted, failed or archived
release_batch_for_retryYour request never left your moduleReturns the batch to pending so it is submitted again
update_paymentFrom your response hook onlySettles one payment from the partner's reply

Prevent double collection

⚠️

Only return move_to_outbox when 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_retry when 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.

FolderHolds
OutboxThe file your module reported sending. Kept for the life of the batch.
ArchiveA copy of the delivered file, in a folder dated by the day it went out.
InboxEvery raw reply from the partner, as it arrived, stamped with the time of receipt.

Batch statuses

StatusDescription
pendingThe batch is built and nothing has been sent.
submittingA run is in progress and the file may be on its way to the partner.
submittedYour module reported the file as sent.
acceptedThe partner confirmed it received the file.
failedThe batch ended without being collected. Final.
archivedThe 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 submitting means 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


Did this page help you?