The interbank workhorse. When one bank tells another 'pay this customer, here's who, here's how much,' it sends a pacs.008. We open it field by field, then let you edit a live one.
Read in the interactive Academy →The problem first. Bob's bank has accepted his instruction. The money is leaving Dubai for Bangalore. But the next bank in the chain has never seen Bob, never seen this payment, and won't take a phone call about it.
This is the one message to learn in depth if you only ever learn one. And the way to really read it is to first work out what the situation forces into it.
{{think}} A machine at the next bank — another country, another system — has to act on this payment with zero ambiguity and no human involved. It's never heard of Bob. It can't ask a follow-up question.
Given all that, what does Bob's bank have to put in the message for that machine to process it safely and pass it on? {{reveal}} Everything that removes ambiguity:
BIC, a code that resolves to exactly one institution anywhere on earth.That message is the pacs.008 — the ISO 20022 successor to the MT103, and by volume one of the most important messages in global finance. {{/think}}
Decode the name once and it's never cryptic again: pacs = Payments Clearing and Settlement; 008 = the FI-to-FI customer credit transfer. Full technical id: pacs.008.001.08 (the trailing numbers are variant and version).
It's strictly bank-to-bank. It is not what Bob's app sends (that's a pain.001). Bob's bank receives the pain.001 and turns it into a pacs.008 to pass onward. Created by the Debtor Agent (Bob's bank), received by the Creditor Agent (Sweety's bank) — directly or through intermediaries. Every hop preserves who pays whom.
See pacs.008 in the Message Explorer →
Two big parts: a Group Header (facts about this hop) and one or more Credit Transfer Transaction blocks (the payment).
<GrpHdr>
<MsgId>BNKAUS33-20260627-000400</MsgId>
<CreDtTm>2026-06-27T09:30:00+04:00</CreDtTm>
<NbOfTxs>1</NbOfTxs>
<SttlmInf><SttlmMtd>INDA</SttlmMtd></SttlmInf>
</GrpHdr>
MsgId — a reference for this hop only. It changes every forward. Point-to-point, disposable.CreDtTm — when the message was created, with a UTC offset (+04:00). Drop the offset and the receiver can't place it in time. A real rejection cause.NbOfTxs — how many transactions inside.SttlmMtd — how the banks settle: across accounts they hold with each other (the nostro/vostro from Level 100) or via a clearing system.<CdtTrfTxInf>
<PmtId>
<EndToEndId>BOB-INV0042</EndToEndId>
<UETR>eb6305c9-1f7c-4a9b-9b1e-2c2f4e7a91d4</UETR>
</PmtId>
<IntrBkSttlmAmt Ccy="USD">400.00</IntrBkSttlmAmt>
<Dbtr><Nm>Bob Marsh</Nm></Dbtr>
<DbtrAgt><FinInstnId><BICFI>EBILAEAD</BICFI></FinInstnId></DbtrAgt>
<CdtrAgt><FinInstnId><BICFI>HDFCINBB</BICFI></FinInstnId></CdtrAgt>
<Cdtr><Nm>Sweety Rao</Nm></Cdtr>
<RmtInf><Ustrd>Invoice 0042 — June freelance</Ustrd></RmtInf>
</CdtTrfTxInf>
The cast you know, now in tags: Dbtr/Cdtr the Debtor (Bob) and Creditor (Sweety); DbtrAgt/CdtrAgt their banks, each a BIC of 8 or 11 characters; IntrBkSttlmAmt the amount that settles between the banks, currency as an attribute; RmtInf/Ustrd what the payment is for.
The single most common interview question on pacs.008 — commit it to memory:
MsgId — point-to-point, rotates every hop, means nothing end to end.EndToEndId — the customer's reference, travels unchanged first bank to last.UETR — a globally unique UUIDv4 identifying the whole payment across every bank; what powers "where is my payment?"{{think}} Here's a pacs.008 that passes every XSD check — well-formed XML, all mandatory elements present. You send it to production and it gets NAK'd anyway. Before reading on: what are the usual culprits? {{reveal}} The failures that live above the schema, in the usage rules and the real world:
EndToEndId of NOTPROVIDED, NA, or empty. It must be a real value, ≤35 chars, that survives every hop.CreDtTm with no UTC offset is ambiguous across borders and gets bounced.Schema-valid and accepted are two different bars, and this gap is exactly where real payments die. {{/think}}
The fastest way to make this stick: edit a real pacs.008 and watch it validate live. The Playground holds Bob's exact transfer — change a name to 40 characters, blank the reference, drop the timezone, and watch each one get caught. You can also run it through the live engine to see it become an MT103 and back.
Edit a live pacs.008 in the Playground →
{{aside:model|The mental model}} pacs.008 is the interbank workhorse — the machine-readable "pay this customer, exactly, no ambiguity." Every hop preserves who pays whom. MsgId rotates per hop; EndToEndId and UETR are the threads that survive the whole journey. {{/aside}}
{{aside:chair|From the engineer's chair}} The rejections that hurt aren't schema errors — they're usage-rule and real-world ones: placeholder EndToEndId, timezone-less CreDtTm, malformed UETR, truncated names. Validating against the raw XSD passes all four. Validate against the usage guideline (CBPR+/HVPS+), and remember the full id pacs.008.001.08 — the version is pinned by the rulebook, not by you. {{/aside}}
{{aside:breaks|Where it breaks}}
{{/aside}}
EndToEndId (NOTPROVIDED/NA/empty) — rejected; breaks the customer's thread.CreDtTm with no UTC offset — ambiguous across borders, bounced.UETR — uppercase or wrong variant bits, no longer a valid UUIDv4.{{aside:map|The map}} The workhorse and its neighbours:
{{/aside}}
{{aside:ref|Reference card}}
{{/aside}}
MsgId (per hop) · EndToEndId (customer, end-to-end) · UETR (global tracking).pacs.008.001.08 — version pinned by the usage guideline.You can open any pacs.008, point to the Group Header and the transaction, name the Debtor/Creditor and their agents, tell MsgId from EndToEndId from UETR without hesitating, and predict the handful of reasons a real payment gets rejected before it ever reaches Sweety.
pacs.008 is best described as… The interbank workhorse that moves a customer's payment between banks
Which reference stays with the payment across every bank, end to end? The UETR — a globally unique tracking reference