Versions & EnvelopesISO 20022 Message Versions

ISO 20022 Message Versions

Which ISO 20022 (MX) message versions transmute reads and writes, how later versions are decoded, how to pick an output version, and the camt .02 and pain.001 .03 downgrades.

Two kinds of version

ISO 20022 messages are versioned individually: camt.053.001.08 is version 8 of the bank-to-customer statement. The version is part of the XML namespace of the Document, so a bank that moves to a newer version changes the namespace your parser sees.

That message version is separate from the yearly Standards Release. The Standards Release decides the rules of a conversion (for example how an address is structured); the message version decides the shape of the XML.

Input: the version is detected

You never name an input version. from is the family (camt.053), and transmute reads the version from the namespace and reports it as meta.detectedVersion. Every version below is detected, converted, normalized and validated:

FamilyAccepted input versionsDefault output version
camt.052, camt.053, camt.054.001.02, .001.08 to .001.12.001.08 (.001.02 on request)
camt.055.001.08input only
camt.056.001.08 to .001.11.001.08
camt.057.001.06 to .001.08.001.06
camt.060.001.05.001.05
camt.029.001.09normalize only
camt.106.001.02.001.02
camt.110.001.02.001.02
camt.111.001.03.001.03
pacs.002.001.10 to .001.14.001.10
pacs.004.001.09 to .001.13.001.09
pacs.008.001.08 to .001.13.001.08
pacs.009.001.08 to .001.11.001.08
pain.001.001.03, .001.09 to .001.12.001.09 (.001.03 on request)
pain.002.001.10 to .001.14normalize only
pain.008.001.08.001.08

The live list for each format is versions in GET /v1/formats. Which formats each one converts to is its convertsTo list there. A version outside the list is a invalid-input 400 whose detail names the accepted versions, for example camt.053 version 001.04 is not supported; accepted versions: 001.02, 001.08, ....

Later versions: decoded, with a warning trail

Versions after the one transmute models in full (for example camt.053.001.12 or pacs.008.001.13) are read with the same decoder. Most of what a later version adds is a new optional element. When the model has no place for such an element yet, it is not silently lost: you get one DROP_FIELD warning with severity info per element path, naming the path and never the value.

curl -sS -X POST "https://api.transmute.403fin.io/v1/normalize" \
  -H "Authorization: Bearer $TRANSMUTE_KEY" \
  -H "Content-Type: application/xml" \
  --data-binary @statement-v12.xml
{ "code": "DROP_FIELD", "severity": "info",
  "sourceField": "Stmt/Ntry/NtryDtls/TxDtls/RltdPties/Dbtr/Pty/PstlAdr/CareOf",
  "detail": "camt.053.001.12 element introduced after the modelled version is not decoded; dropped" }

Later versions are input only. Naming one as an output version is a unsupported-format 422:

{
  "type": "https://docs.transmute.403fin.io/errors/unsupported-format",
  "title": "Unsupported format",
  "status": 422,
  "detail": "Unsupported target version "001.12" for camt.053",
  "instance": "/v1/convert"
}

Output: choose a version

Without a choice, an MX target is written in its default output version (the table above), reported as meta.targetType (camt.053.001.08). To choose, use targetVersion:

FormWhere
JSON envelopeoptions.targetVersion
Query parameter?toVersion=
HeaderX-Transmute-To-Version

camt.053.001.02, 001.02 and 02 are all accepted spellings. Only two families have a second output version:

  • camt.052, camt.053 and camt.054 can be written as .001.02;
  • pain.001 can be written as .001.03.

camt .08 to .02

Some importers still read only camt .001.02. Ask for it, from any source that converts to camt.052, camt.053 or camt.054:

curl -sS -X POST "https://api.transmute.403fin.io/v1/convert?to=camt.053&toVersion=camt.053.001.02" \
  -H "Authorization: Bearer $TRANSMUTE_KEY" \
  -H "Content-Type: application/xml" \
  --data-binary @statement-v08.xml
# "meta": {"detectedVersion": "camt.053.001.08", "targetType": "camt.053.001.02", ...}

.02 has no place for a few things that .08 can carry. Each one that is present is handled like this:

ContentIn .02Warning
Transaction UETR (Refs/UETR)DroppedDROP_FIELD (lossy)
Proprietary entry status (Sts/Prtry)Status becomes INFO, so the entry is never presented as bookedDROP_FIELD (lossy)
Entry status code other than BOOK, PDNG, INFOStatus becomes INFODROP_FIELD (lossy)
Related debtor or creditor given only as an agent (RltdPties/Dbtr/Agt, RltdPties/Cdtr/Agt)DroppedDROP_FIELD (lossy)
Account proxy (Acct/Prxy)DroppedDROP_FIELD (lossy)
Balance type code outside the .02 code listCarried as a proprietary type (Tp/CdOrPrtry/Prtry)CODE_UNMAPPED_PROPRIETARY (info)

With strict: true, any of the lossy drops fails the conversion instead.

pain.001 .03 and .09

pain.001 also converts to itself, as a version bridge between .001.03 (still common on corporate banking portals) and .001.09:

  • .001.03 input is upgraded to .001.09 by default.
  • targetVersion=pain.001.001.03 downgrades .001.09 or later input. It also works with from=mt101.
curl -sS -X POST "https://api.transmute.403fin.io/v1/convert?to=pain.001&toVersion=pain.001.001.03" \
  -H "Authorization: Bearer $TRANSMUTE_KEY" \
  -H "Content-Type: application/xml" \
  --data-binary @initiation-v09.xml

What .001.03 cannot carry is dropped with DROP_FIELD (lossy), or refused under strict:

ContentWhy
A UETR.001.03 has no UETR element
A second service level.001.03 holds one
The time part of a requested execution date-time.001.03 holds a date only
A BIC that does not match the older BIC pattern.001.03 validates BICs more narrowly

Output in .001.03 validates against the pain.001.001.03 schema.

  • MX to MX conversions: camt.052 to camt.053 and re-rendering a statement, which upgrades .02 input to clean .08 output.
  • Convert: the full option list.