Normalize-only Formats
MT199 and MT299 free-format messages, camt.029 resolutions of investigation and pain.002 status reports: formats you can normalize and validate but not convert from.
Formats
| Format | What it is | Versions accepted | Normalized result.type |
|---|---|---|---|
mt199 | Free format message (customer side) | n/a | investigation, kind free-format |
mt299 | Free format message (bank side) | n/a | investigation, kind free-format |
camt.029 | Resolution of investigation | .001.09 | investigation, kind answer |
pain.002 | Customer payment status report | .001.10 – .001.14 | status |
All four work with /v1/normalize and /v1/validate. None of them is a conversion source: /v1/convert with one of them as from (or detected as the source) returns 422 unsupported-conversion. GET /v1/formats lists them with an empty convertsTo.
Why they do not convert
- MT199 / MT299. A free-format message is one block of text (
:79:). The nearest structured MX message, a camt.110 investigation request, needs an investigation type, a requester and responder, and a reference to an underlying transaction. A free text carries none of these, so any conversion would invent most of its target. - camt.029. The answer to a cancellation request can describe the outcome in detail (modification details, claims of non-receipt, corrected transactions and other resolution data) that no format in the conversion families can hold faithfully. It normalizes to an answer so you can read it alongside MT196/MT296 and camt.111 answers.
- pain.002. The customer status report has no MT counterpart. transmute can still produce a pain.002 from a canonical
statusdocument (see Rejects and status reports); it just cannot convert one into another format.
What normalization extracts
MT199 / MT299. :20: becomes the case id and :21: the original end-to-end id. Every :79: line is kept as narrative, in order. One kind of line is also read as data: a tracker status line of the form //SSSS or //SSSS/RRRR whose SSSS is ACCC, ACSC, ACSP, PDNG or RJCT sets status, and RRRR is added to reasonCodes. Only the first such line counts, and it stays in the narrative too. No amount is ever read from free text.
camt.029. The confirmation status becomes status (falling back to the first transaction's cancellation status); the resolved case id, assigner and creation time, the first transaction's original references, amount and date, its reason codes and additional information are kept. Further transactions and the detailed resolution branches are reported with DROP_FIELD (info).
pain.002. The group header, the original group information and status, and one entry per transaction with its status, reason code, additional information and original references (including OrgnlTxRef amount and date when present).
Detecting MT199 and MT299
A message whose only content field is :79: (no :75:, :76:, :77A:, :11S: or :11R:) is detected as mt199. A bare MT299 is byte-for-byte identical, so it also detects as mt199; send the FIN envelope (block 2 299) or from=mt299 when you need the distinction.
Example
curl -sS -X POST "https://api.transmute.403fin.io/v1/normalize" \
-H "Authorization: Bearer $TRANSMUTE_KEY" \
-H "Content-Type: text/plain" \
--data-binary @- <<'MT'
:20:TRK-2026-0007
:21:PAY-2026-0042
:79://2606101315+0100
//ACSP/G000
//EUR1000,00
CREDITED TO BENEFICIARY ACCOUNT
MT
{
"result": {
"type": "investigation",
"investigation": {
"kind": "free-format",
"caseId": "TRK-2026-0007",
"originalEndToEndId": "PAY-2026-0042",
"reasonCodes": ["G000"],
"status": "ACSP",
"narrative": [
"//2606101315+0100",
"//ACSP/G000",
"//EUR1000,00",
"CREDITED TO BENEFICIARY ACCOUNT"
]
}
},
"warnings": [],
"meta": { "detectedType": "mt199", "detectedVersion": "", "durationMs": 0 }
}
The tracker line //ACSP/G000 fills status and reasonCodes; the time stamp and the amount line stay narrative only.