Integration recipes#

Open, copyable patterns for wiring Pain001 into a payments pipeline. Each recipe runs on your own infrastructure. examples/30_integration_recipes.py runs recipes 1, 2, 4 and 5 end to end on synthetic data, and CI runs it on every change. Contributions of new recipes are welcome.

1. ERP or treasury CSV export to pain.001#

Most ERP and treasury systems can export a payment run as CSV. Map its columns onto Pain001’s input columns (listed in the input-column reference), and take the batch-level fields (debtor, initiating party, execution date) from your own configuration.

MAPPING = {
    "Invoice": "payment_id",
    "Supplier": "creditor_name",
    "SupplierIBAN": "creditor_account_IBAN",
    "SupplierBIC": "creditor_agent_BIC",
    "Amount": "payment_amount",
    "Currency": "payment_currency",
}

pain001 init pain.001.001.09 -o payments.csv writes a scaffold with every column the message type needs; the example’s map_export function shows the whole mapping.

2. Batch pipeline#

validate and generate read the files you name on the command line from any directory; from Python, data files must be under the working directory.

pain001 validate -t pain.001.001.09 -d payments.csv
pain001 generate -t pain.001.001.09 -d payments.csv -o out
pain001 check out/pain.001.001.09.xml

Add --scheme sepa-sct (or another rail) and a private bank profile (--rules, --schematron) to check more than the schema. pain001 check --format sarif writes a report for code scanning, and the GitHub Action in this repository’s action.yml (uses: sebastienrousseau/pain001@v<version>) runs check in your own CI.

To send and collect files over SFTP, add pain001 upload and pain001 download (the upload extra) as described in the SFTP guide. Schedule the pipeline with cron or a systemd timer; Pain001 runs no daemon.

3. API pipeline#

pain001 serve (the api extra) exposes the same steps over REST: POST /api/v1/validate, POST /api/v1/generate (and /api/v1/generate/async with job status and download) and POST /api/v1/check for an XML document you send. Without PAIN001_API_KEY the server binds only loopback. examples/05_api_job_lifecycle.py and examples/26_rest_server.py run these calls.

4. pain.002 status reports#

The bank answers a pain.001 with a pain.002 status report. pain001 status reads it and exits 3 when any group, payment block or transaction was rejected, so a scheduled job can alert on it:

pain001 status replies/*.xml            # exit 0 accepted, 3 rejected
pain001 status --format json replies/*.xml

Each rejected item is listed with its reason code (for example AC04, closed account). From Python, parse_pain002_report returns the same data.

5. camt.052, camt.053 and camt.054 reconciliation#

Install the camt extra to read cash-management reports through the camt053 package:

pip install "pain001[camt]"
pain001 status statements/*.xml

To reconcile, match each statement entry’s end-to-end identifier with the payments you sent:

import camt053
from pain001.corpus.rules.projection import rows_from_xml

sent = {r["end_to_end_id"] for r in rows_from_xml(pain001_xml)}
statement = camt053.parse_document(camt_xml)
booked = {d.end_to_end_id for e in statement.all_entries() for d in e.details}
open_items = sorted(sent - booked)

open_items are the payments not yet booked, for example the one the bank rejected in its pain.002.