{"openapi":"3.1.0","info":{"title":"ISO 20022 Navigator API","version":"1.0.0","summary":"Detect, parse, validate and convert ISO 20022 camt/pain messages and SWIFT MT940/MT942 statements.","description":"Keyless and free. Each visitor (an IPv4 address or an IPv6 /64) may make 60 requests a minute; bodies are capped at 256 KB. Request bodies are processed in memory and never stored or logged. Amounts in responses are exact decimal strings. The same operations are available to AI agents as an MCP server at https://iso20022-navigator.com/mcp (Streamable HTTP, stateless, JSON responses).","contact":{"name":"ISO 20022 Navigator","email":"davidkaylor95+iso20022@gmail.com","url":"https://iso20022-navigator.com/api"}},"servers":[{"url":"https://iso20022-navigator.com"}],"externalDocs":{"description":"API and MCP guide","url":"https://iso20022-navigator.com/api"},"paths":{"/api/v1/detect":{"post":{"operationId":"detectMessageType","summary":"Identify a message type","description":"Identify a payment or bank-statement file. Recognizes ISO 20022 XML by its namespace (urn:iso:std:iso:20022:tech:xsd:camt.053.001.08) or, without one, by the element under <Document> — camt.052/053/054, pain.001/002/008, pacs.002/003/004/008/009, camt.029/055/056/060 and more — and SWIFT MT940/MT942/MT950 by their blocks and fields. Returns the message type, the full identifier with version, the message name, whether this server can parse, validate and convert it, the business application header (head.001) if present, and notes. Cheap: reads only the start of the content.","requestBody":{"required":true,"description":"The file: either the raw text as the body (any text content type), or JSON {\"content\": \"<file text>\"}. At most 256 KB. Send UTF-8. A charset parameter in Content-Type is honoured (415 for a charset the server does not read, 400 for bytes that do not fit it). Without one the body is read as UTF-8, as UTF-16 when it starts with a byte-order mark, else as Latin-1 (Windows-1252); XML that is not UTF-8 then gets an xml.encoding error, while an MT940 in Latin-1 reads normally. Nothing is decoded lossily. A JSON body must be UTF-8.","content":{"text/plain":{"schema":{"type":"string"}},"application/xml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","required":["content"],"additionalProperties":false,"properties":{"content":{"type":"string","description":"The complete file text (ISO 20022 XML or SWIFT MT940/MT942)."}}}}}},"responses":{"200":{"description":"What the file is.","content":{"application/json":{"schema":{"type":"object","required":["detection"],"properties":{"detection":{"$ref":"#/components/schemas/Detection"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedCharset"},"429":{"$ref":"#/components/responses/TooMany"}}}},"/api/v1/parse":{"post":{"operationId":"parseMessage","summary":"Parse to normalized JSON","description":"Parse an ISO 20022 XML message into normalized JSON. camt.052 (intraday account report), camt.053 (bank-to-customer statement) and camt.054 (debit/credit notification): per statement the account (IBAN or other id, currency, owner, servicer BIC), statement id, sequence numbers, period, balances (type code such as OPBD/CLBD/CLAV/ITBD, amount, credit/debit, date) and entries (amount, CRDT/DBIT, status BOOK/PDNG/INFO, reversal flag, booking and value dates, bank transaction code domain/family/sub-family with its meaning, AcctSvcrRef, batch info, and per transaction detail the EndToEndId/InstrId/MsgId/UETR, counterparty name/IBAN/BIC, remittance text and creditor reference, return reason). pain.001 (credit transfers) and pain.008 (direct debits): group header, payment information blocks and transactions. pain.002: original message, group/block/transaction statuses with reason codes. Amounts are exact decimal strings; every element carries its line number. Accepts versions .001.02 to .001.13 and any namespace prefix. Also accepts MT940/MT942 (same result as parse_mt940). Includes a summary and issue counts; call validate_payment_file for the list of issues.","requestBody":{"required":true,"description":"The file: either the raw text as the body (any text content type), or JSON {\"content\": \"<file text>\"}. At most 256 KB. Send UTF-8. A charset parameter in Content-Type is honoured (415 for a charset the server does not read, 400 for bytes that do not fit it). Without one the body is read as UTF-8, as UTF-16 when it starts with a byte-order mark, else as Latin-1 (Windows-1252); XML that is not UTF-8 then gets an xml.encoding error, while an MT940 in Latin-1 reads normally. Nothing is decoded lossily. A JSON body must be UTF-8.","content":{"text/plain":{"schema":{"type":"string"}},"application/xml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","required":["content"],"additionalProperties":false,"properties":{"content":{"type":"string","description":"The complete file text (ISO 20022 XML or SWIFT MT940/MT942)."}}}}}},"responses":{"200":{"description":"The parsed message.","content":{"application/json":{"schema":{"type":"object","required":["detection","summary","counts","document"],"properties":{"detection":{"$ref":"#/components/schemas/Detection"},"summary":{"$ref":"#/components/schemas/Summary"},"counts":{"$ref":"#/components/schemas/Counts"},"document":{"type":"object","description":"The parsed message: kind \"camt\" (statements), \"pain\" (paymentInfos or statusReport) or \"mt\" (statements). Every block carries its line number."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedCharset"},"422":{"description":"Not a supported message, or not well-formed XML; issues say why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooMany"}}}},"/api/v1/validate":{"post":{"operationId":"validateMessage","summary":"Validate and list issues","description":"Validate a camt.052/053/054, pain.001/002/008 or MT940/MT942 file and list every finding with a stable rule id, severity (error, warning or info), message, XPath-like path and line number, and the found/expected values when they help. Checks: XML well-formedness; required elements; balance roll-forward (opening booked balance + booked entries = closing booked balance; MT940 :60a: + :61: = :62a:); transaction summary (TxsSummry) and batch totals against the entries; NbOfTxs and CtrlSum at group-header and payment-information level; IBAN format, country length and mod-97 check digits; BIC format; ISO 4217 currency codes and decimals; Max35Text/Max140Text lengths; ISO dates; duplicate EndToEndId, PmtInfId, InstrId and AcctSvcrRef; requested execution or collection date in the past; SEPA rules when the service level is SEPA (EUR only, IBANs required, SEPA character set, 70-character names, one remittance line, SLEV, creditor id and mandate data for direct debits); pain.002 rejections without reasons and status consistency; MT940 field formats, lengths, character set, currencies and page chaining. \"valid\" is true when there are no errors; rules banks apply unevenly are warnings, not errors.","requestBody":{"required":true,"description":"The file: either the raw text as the body (any text content type), or JSON {\"content\": \"<file text>\", \"today\": \"YYYY-MM-DD\"}. At most 256 KB. Send UTF-8. A charset parameter in Content-Type is honoured (415 for a charset the server does not read, 400 for bytes that do not fit it). Without one the body is read as UTF-8, as UTF-16 when it starts with a byte-order mark, else as Latin-1 (Windows-1252); XML that is not UTF-8 then gets an xml.encoding error, while an MT940 in Latin-1 reads normally. Nothing is decoded lossily. A JSON body must be UTF-8.","content":{"text/plain":{"schema":{"type":"string"}},"application/xml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","required":["content"],"additionalProperties":false,"properties":{"content":{"type":"string","description":"The complete file text (ISO 20022 XML or SWIFT MT940/MT942)."},"today":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"A real calendar date used as \"today\" for date checks. Default: current UTC date."}}}}}},"responses":{"200":{"description":"Validation result. An unsupported or malformed file is a 200 with valid false and the reason as an issue.","content":{"application/json":{"schema":{"type":"object","required":["detection","valid","summary","counts","truncated","issues"],"properties":{"detection":{"$ref":"#/components/schemas/Detection"},"valid":{"type":"boolean","description":"True when there are no errors."},"summary":{"$ref":"#/components/schemas/Summary"},"counts":{"$ref":"#/components/schemas/Counts"},"truncated":{"type":"boolean","description":"At most 500 issues per rule and severity are listed; counts include all."},"issues":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedCharset"},"429":{"$ref":"#/components/responses/TooMany"}}}},"/api/v1/convert/mt940-to-camt053":{"post":{"operationId":"convertMt940ToCamt053","summary":"Convert MT940 to camt.053.001.08","description":"Convert SWIFT MT940 (or MT950) statements to one ISO 20022 camt.053.001.08 XML document: one Stmt per MT940 statement, one Ntry with one TxDtls per :61:. Balances become OPBD/CLBD/CLAV/FWAV, :61: type codes are kept as proprietary bank transaction codes (BkTxCd/Prtry, issuer SWIFT) rather than guessed ISO domain codes, structured :86: subfields become counterparty, account, agent, EndToEndId, MndtId and remittance. Returns the XML string, its message id, statement and entry counts, notes describing the mapping and its limits for this file, and the validation issues of the MT940 input. Refuses input whose balances or entries cannot be read rather than dropping data; MT942 is refused (it maps to camt.052). Accepts MT940 files up to 128 KB. Responds with the XML itself (application/xml) unless the request's Accept header prefers application/json, which returns the XML inside a JSON object with the notes and input issues.","requestBody":{"required":true,"description":"The file: either the raw text as the body (any text content type), or JSON {\"content\": \"<file text>\"}. At most 256 KB. Send UTF-8. A charset parameter in Content-Type is honoured (415 for a charset the server does not read, 400 for bytes that do not fit it). Without one the body is read as UTF-8, as UTF-16 when it starts with a byte-order mark, else as Latin-1 (Windows-1252); XML that is not UTF-8 then gets an xml.encoding error, while an MT940 in Latin-1 reads normally. Nothing is decoded lossily. A JSON body must be UTF-8.","content":{"text/plain":{"schema":{"type":"string"}},"application/xml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","required":["content"],"additionalProperties":false,"properties":{"content":{"type":"string","description":"The complete file text (ISO 20022 XML or SWIFT MT940/MT942)."}}}}}},"responses":{"200":{"description":"The camt.053.001.08 document.","headers":{"X-Statements":{"schema":{"type":"integer"}},"X-Entries":{"schema":{"type":"integer"}}},"content":{"application/xml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","properties":{"messageType":{"const":"camt.053.001.08"},"messageId":{"type":"string"},"statements":{"type":"integer"},"entries":{"type":"integer"},"xml":{"type":"string"},"notes":{"type":"array","items":{"type":"string"}},"inputCounts":{"$ref":"#/components/schemas/Counts"},"inputIssues":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"413":{"$ref":"#/components/responses/TooLarge"},"415":{"$ref":"#/components/responses/UnsupportedCharset"},"422":{"description":"Not an MT940, or fields that could not be read (nothing is converted rather than dropping data).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooMany"}}}},"/api/v1/explain":{"get":{"operationId":"explainCode","summary":"Explain a code","description":"Explain an ISO 20022 or SWIFT code in plain words, with where it appears. Covers balance types (OPBD, CLBD, CLAV, OPAV, ITBD, ITAV, PRCD, FWAV, XPCD, INFO), bank transaction codes (a domain, family or sub-family such as PMNT, RCDT, ESCT, or a full \"PMNT/RCDT/ESCT\"), entry statuses (BOOK, PDNG, INFO, FUTR), payment statuses (RCVD, ACTC, ACCP, ACSP, ACSC, ACCC, PDNG, PART, RJCT, CANC…), status and return reason codes (AC01, AC04, AM04, MS03, MD07, RR04…), MT940 :61: transaction types (NTRF, NCHG, NDDT, S103 or the 3-letter TRF), message types (camt.053, pain.001.001.09) and ISO 4217 currency decimals (JPY, KWD). With kind \"auto\" every table is searched, so a code used in several (PDNG) returns each meaning.","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string","maxLength":64},"example":"AC01"},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["auto","balance_type","bank_transaction_code","entry_status","payment_status","status_reason","mt940_transaction_type","message_type","currency"],"default":"auto"}}],"responses":{"200":{"description":"Matches from the code tables: empty with a note when nothing matched; a note also names the parts of a bank transaction code that are not in the reference lists.","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"kind":{"type":"string"},"matches":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"},"definition":{"type":"string"},"usedIn":{"type":"string"}}}},"note":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooMany"}}}},"/api/health":{"get":{"operationId":"health","summary":"Health check","responses":{"200":{"description":"The Worker is up.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"const":"ok"}}}}}}}}}},"components":{"schemas":{"Detection":{"type":"object","properties":{"kind":{"enum":["iso20022","mt","xml","unknown"]},"messageType":{"type":["string","null"],"examples":["camt.053","pain.001","mt940"]},"identifier":{"type":["string","null"],"examples":["camt.053.001.08"]},"version":{"type":["string","null"]},"name":{"type":["string","null"]},"rootElement":{"type":["string","null"]},"namespace":{"type":["string","null"]},"basis":{"enum":["namespace","root-element","content",null]},"supported":{"type":"boolean","description":"This API parses and validates it."},"convertible":{"type":"boolean","description":"The MT940 → camt.053 conversion accepts it."},"viewerUrl":{"type":["string","null"],"description":"The browser viewer for this file type."},"appHeader":{"type":["object","null"]},"notes":{"type":"array","items":{"type":"string"}}}},"Summary":{"type":"object","properties":{"messageType":{"type":["string","null"]},"statements":{"type":"integer"},"entries":{"type":"integer"},"transactions":{"type":"integer"},"paymentBlocks":{"type":"integer"},"valid":{"type":"boolean"}}},"Counts":{"type":"object","properties":{"error":{"type":"integer"},"warning":{"type":"integer"},"info":{"type":"integer"}}},"Issue":{"type":"object","required":["rule","severity","message","path","line","title"],"properties":{"rule":{"type":"string","enum":["format.empty","format.unknown","format.unsupported","xml.malformed","xml.encoding","xml.namespace","xml.version","field.required","field.empty","field.length","field.date","field.amount","field.number","field.indicator","ccy.format","ccy.unknown","ccy.decimals","ccy.mismatch","iban.invalid","iban.country","bic.format","bic.country","code.unknown","code.invalid","ref.duplicate","camt.balance.roll-forward","camt.balance.missing","camt.balance.multiple","camt.summary.count","camt.summary.sum","camt.batch.count","camt.batch.sum","camt.entry.status","camt.entry.booking-date","camt.dates.order","camt.pagination","pain.count.group","pain.sum.group","pain.count.payment","pain.sum.payment","pain.date.past","pain.duplicate.pmtinf","pain.duplicate.e2e","pain.duplicate.instr","pain.amount.zero","pain.party.name","pain.status.reason","pain.status.mix","pain.status.counts","sepa.currency","sepa.iban-required","sepa.charset","sepa.name-length","sepa.remittance","sepa.charge-bearer","sepa.amount-range","sepa.country","sepa.creditor-id","sepa.mandate","sepa.sequence-type","mt.block","mt.field.required","mt.field.format","mt.field.order","mt.field.length","mt.charset","mt.balance.roll-forward","mt.balance.continuity","mt.sequence","mt.currency","mt.date","mt.summary"],"description":"Stable rule id."},"title":{"type":"string"},"severity":{"enum":["error","warning","info"]},"message":{"type":"string"},"path":{"type":["string","null"],"description":"XPath-like location, e.g. /Document/BkToCstmrStmt/Stmt[2]/Ntry[3]/Amt, or Stmt[1]/:61:[2] for MT."},"line":{"type":["integer","null"]},"found":{"type":"string"},"expected":{"type":"string"},"hint":{"type":"string"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"detection":{"$ref":"#/components/schemas/Detection"},"counts":{"$ref":"#/components/schemas/Counts"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}}}}},"responses":{"BadRequest":{"description":"Empty content; a JSON body without a \"content\" string, or not UTF-8; bytes that do not fit the declared charset; \"today\" not a real date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"UnsupportedCharset":{"description":"The Content-Type names a charset the server does not read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooLarge":{"description":"The body is over 256 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooMany":{"description":"More than 60 requests in a minute from this visitor.","headers":{"Retry-After":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}