Payment spreadsheets
Turn a CSV or XLSX sheet of payments into an MT101 or pain.001 credit transfer: sending the file, mapping your column headers, amounts, dates, batching and limits.
A sheet of payments in, a payment file out
Payment runs often start life as a spreadsheet. Two source formats read them:
| Format id | Input | Converts to |
|---|---|---|
csv-payments | CSV text, UTF-8, delimiter , ; or tab (detected from the header row) | pain.001, mt101 |
xlsx-payments | an Excel workbook; the first sheet is read | pain.001, mt101 |
pain.001 is the ISO 20022 customer credit transfer initiation, and mt101 is its MT counterpart. Spreadsheets are never auto-detected because any sheet could be anything, so from is required. Without it the response is unsupported-format 422, telling you to set from to csv-payments or xlsx-payments.
curl -sS -X POST "https://api.transmute.403fin.io/v1/convert?from=csv-payments&to=pain.001" \
-H "Authorization: Bearer $TRANSMUTE_KEY" \
-H "Content-Type: text/csv" \
--data-binary @- <<'EOF'
creditor_name,creditor_iban,amount,currency,execution_date,debtor_name,debtor_iban,remittance
EXAMPLE LTD,GB29NWBK60161331926819,1250.00,EUR,2026-06-09,EXAMPLE GMBH,DE89370400440532013000,INVOICE 1001
EOF
The result is a pain.001.001.09 with one payment batch for the debtor DE89370400440532013000, executing on 2026-06-09, holding one 1250.00 EUR transfer to EXAMPLE LTD. Required values the sheet doesn't carry, such as the message id, are defaulted and reported with MISSING_REQUIRED_DEFAULTED.
Sending the file
| Form | How |
|---|---|
| Raw CSV | Content-Type: text/csv, options as query parameters |
| Raw XLSX | Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, --data-binary @payments.xlsx |
| JSON envelope | message holds the CSV text; for XLSX, message is the base64 of the workbook and messageEncoding is "base64" |
| File upload | the file as the file part of a multipart/form-data request, with from, to and options as form fields |
Mapping your headers
A header row is required. Each header is matched case-insensitively, with spaces, hyphens and dots treated like _. It is resolved in this order:
- your
options.columnMap, - the default header names below,
- the target path spelled out (
creditor.name).
columnMap maps your header to a path, or to ignore to skip the column silently:
{
"from": "csv-payments",
"to": "mt101",
"message": "Payee;Payee IBAN;Betrag;Currency;Execution Date;Notes
...",
"options": {
"columnMap": { "Payee": "creditor.name", "Payee IBAN": "creditor.iban", "Betrag": "amount", "Notes": "ignore" },
"numberFormat": "comma"
}
}
On raw requests, pass it as a JSON object string: ?columnMap={"Payee":"creditor.name","Betrag":"amount"} (URL-encoded).
| Path | Default headers | Level |
|---|---|---|
msgId | msg_id, message_id | file |
initiatingParty.name | initiating_party | file |
paymentInfoId | payment_info_id, batch_id | batch |
executionDate | execution_date, payment_date | batch |
debtor.name | debtor_name | batch |
debtor.iban, debtor.account | debtor_iban, debtor_account | batch |
debtor.bic | debtor_bic | batch |
endToEndId | end_to_end_id, reference | payment |
instrId | instruction_id | payment |
uetr | uetr | payment |
amount | amount | payment |
currency | currency, ccy | payment |
creditor.name | creditor_name, beneficiary_name, payee | payment |
creditor.iban, creditor.account | creditor_iban, beneficiary_iban, creditor_account, beneficiary_account | payment |
creditor.bic | creditor_bic, beneficiary_bic | payment |
creditor.address.street, .buildingNumber, .postCode, .town, .country | creditor_street, creditor_building_number, creditor_postcode, creditor_town or creditor_city, creditor_country | payment |
intermediary.bic | intermediary_bic | payment |
remittance | remittance, remittance_info, memo | payment (one remittance line per line break in the cell) |
purpose | purpose, purpose_code | payment |
chargeBearer | charge_bearer, charges | payment (DEBT, CRED, SHAR, SLEV, or OUR, BEN, SHA) |
fxContractRef | fx_contract_ref | payment |
exchangeRate | exchange_rate | payment |
originalAmount, originalCurrency | original_amount, original_currency | payment |
amount, currency and creditor.name are required. A column that matches nothing is ignored and reported with COLUMN_UNMAPPED (info). The warning's sourceField is columns[N] (the column position), and it never quotes your header text or cell values.
These are invalid-input 400: a missing required column, two columns resolving to the same path, or an unknown path in columnMap.
Amounts and dates
- Amounts.
options.numberFormatsets the separators for the whole file:point(default,1,234.56) orcomma(1.234,56). It is never guessed per cell. Spaces and apostrophes are removed. A zero or negative amount, more decimals than the currency allows, or any other character is a 400 naming the row number and the path, never the cell. Excel stores numbers with a decimal point, soxlsx-paymentsrejectscomma. - Dates.
YYYY-MM-DD(optionally with a time),YYYYMMDDandYYYY/MM/DDare always accepted. Day/month layouts needoptions.dateFormat:dmyacceptsDD/MM/YYYY,DD.MM.YYYYandDD-MM-YYYY;mdyacceptsMM/DD/YYYY. An ambiguous date withoutdateFormatis rejected, never guessed. Excel date cells are read as dates.
Batching
Rows that share the same payment info id, execution date and debtor details form one batch, in the order they first appear. File-level values such as msgId come from the first row that has them. A different value in a later row is dropped with a lossy DROP_FIELD naming the row.
An MT101 needs an execution date. A sheet without one converts to pain.001 but not to mt101 (400).
Limits
| Limit | Value |
|---|---|
| Data rows | 50,000 |
| Columns | 256 |
| Bytes per cell | 4096 |
| Encoding | UTF-8 (a leading byte-order mark is ignored) |
| XLSX | first sheet only; workbooks over the size limits fail with workbook exceeds a size limit |
The request body limit of /v1/convert applies to the file. Empty rows are skipped, and a row with values in columns beyond the header is rejected.
columnMap and numberFormat apply to synchronous /v1/convert; batch items don't carry them. All warning codes are in the warning registry.