We're still building. The app is in closed testing.

SWIFT MT ↔ ISO 20022

Convert SWIFT MT to ISO 20022 in one API call

A stateless, API-first service that converts SWIFT MT messages to and from ISO 20022, normalizes either format to clean JSON, and validates at selectable strictness. Message bodies arenever persisted and never logged; completing a request leaves behind exactly one row of usage metadata.

Free tier: 1,000 live conversions / month · no card required.

0 bodies
stored or logged

Message contents live in request-scoped memory only. The database keeps metadata: type, size, duration, status, warning codes.

≤ 24h
the only two exceptions

Idempotency cache (24h TTL) and the encrypted async batch store (purged on completion; TTL ≤ 24h). Nothing else touches payload content.

EU-only
single region

All processing and backups stay in the EU. Statelessness makes right-to-erasure trivial: for payloads there is nothing to erase.

Stateless by design

  • Bodies processed in request-scoped memory only
  • Metadata-only Postgres (type, size, duration, status)
  • Logging middleware is structurally body-free
  • Amounts as decimals, never floats

Capabilities

Everything the conversion engine actually does

Grounded in the real product surface: every card maps to a documented endpoint or feature, not a roadmap promise.

MT ↔ ISO 20022

Convert SWIFT MT statements and transfers to and from ISO 20022 MX: MT940 / MT942 / MT950 ↔ camt.053 / camt.052, MT103 ↔ pacs.008, and MT202 / MT205 ↔ pacs.009. MX versions auto-detected on input.

Normalize to JSON

Parse either format into one frozen, stable canonical JSON shape built for bookkeeping and reconciliation, with amounts always as strings, never floats.

Validation

Syntax and schema validation at selectable strictness levels, including CBPR+ checks. Always returns 200 with valid + findings[]; MX output validates against vendored ISO 20022 XSDs.

Enrichment

IBAN / BIC / code checks against free registry data, with a bring-your-own BIC directory plug point. Licensed directory data is never bundled.

Batch + webhooks

Async batch conversion with job polling and signed job.completed webhooks (retry ladder, X-Transmute-Signature).

Connectors

File-drop / SFTP connectors move files between customer-owned directories (in/ → out/); nothing enters our custody.

On-prem / self-hosted

License-mode deployment for Enterprise: unlimited within license, rate limiting preserved, your infrastructure.

Structured warnings

Lossy or assumed conversion steps surface as deterministic, severity-graded warnings in the response; nothing is dropped silently.

Directed pairs in the engine

MT940customer statementcamt.053camt.052
MT942interim reportcamt.052camt.053
MT950statementcamt.053camt.052
camt.053bank-to-customer statementMT940MT950
camt.052bank-to-customer reportMT940MT950
MT103single customer credit transferpacs.008
pacs.008FI-to-FI customer credit transferMT103
MT202 / MT205financial-institution transferpacs.009
pacs.009FI credit transferMT202MT205

Every parseable format additionally normalizes to canonical JSON. The full registry is served live by the engine at GET /v1/formats.

One call

Convert MT940 to camt.053

Authenticate with a bearer key, POST the message, get back the converted document plus severity-graded warnings and metadata. Raw MT text and bare XML work too.

curl -sS -X POST https://api.transmute.403fin.io/v1/convert \
  -H "Authorization: Bearer $TRANSMUTE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"mt940","to":"camt.053","message":"..."}'
const res = await fetch("https://api.transmute.403fin.io/v1/convert", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TRANSMUTE_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ from: "mt940", to: "camt.053", message }),
});
const { result, warnings, meta } = await res.json();
import os, requests

res = requests.post(
    "https://api.transmute.403fin.io/v1/convert",
    headers={"Authorization": f"Bearer {os.environ['TRANSMUTE_KEY']}"},
    json={"from": "mt940", "to": "camt.053", "message": message},
)
data = res.json()  # {"result": "...camt.053...", "warnings": [...], "meta": {...}}
req, _ := http.NewRequest("POST",
    "https://api.transmute.403fin.io/v1/convert",
    strings.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TRANSMUTE_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)

Full request body omitted for brevity; see the message payload in the quickstart. Sample data is synthetic (published example IBAN, TEST BICs).

Three steps, zero retained payload

1

Send the message

POST raw MT text, bare ISO 20022 XML, or a JSON envelope with from/to. Authenticate with a bearer API key.

2

It converts in memory

The engine parses, maps via declarative SR-versioned tables, and renders the target, all in request-scoped memory. Nothing is stored.

3

Get result + warnings

Receive the converted document (or canonical JSON) plus deterministic, severity-graded warnings. One row of usage metadata is all that remains.

Start converting today

Free tier: 1,000 live conversions a month, no card required.