File size: 47,025 Bytes
319bc81
12d828f
 
 
 
f350314
 
12d828f
 
 
 
 
 
 
 
 
 
 
 
 
 
f350314
12d828f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f350314
 
12d828f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f350314
 
 
 
12d828f
f350314
 
12d828f
 
f350314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319bc81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Cbpr+ Address requirements — check your payment xml free</title>
<meta name="description" content="This free browser tool checks ISO 20022 payment XML for unstructured addresses, missing country or town names, and duplicated address values.">
<style>
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
.buy{margin-top:12px}.buy a{display:inline-block;background:#1f4e5f;color:#fff;text-decoration:none;padding:10px 16px;border-radius:8px;font-weight:600}.terms{font-size:12px;color:#7a6e65;margin-top:8px}.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
</style>
<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/cbpr-address-lint"></head>
<body>
<div class="wrap">
<h1>Cbpr+ Address requirements — check your payment xml free</h1>
<p class="lede">Lint ISO 20022 pacs.008, pacs.009 and pain.001 XML for postal addresses CBPR+ will not accept: unstructured blocks, missing Ctry or TwnNm, and values duplicated between a structured field and AdrLine. Runs entirely in your browser — nothing is uploaded.</p>
<textarea id="src" spellcheck="false">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08"&gt;
  &lt;FIToFICstmrCdtTrf&gt;
    &lt;GrpHdr&gt;
      &lt;MsgId&gt;CBPR-DIRTY-0001&lt;/MsgId&gt;
      &lt;CreDtTm&gt;2026-09-20T09:15:00Z&lt;/CreDtTm&gt;
      &lt;NbOfTxs&gt;1&lt;/NbOfTxs&gt;
    &lt;/GrpHdr&gt;
    &lt;CdtTrfTxInf&gt;
      &lt;PmtId&gt;
        &lt;UETR&gt;b7c8d9e0-2222-4333-8444-555566667777&lt;/UETR&gt;
      &lt;/PmtId&gt;
      &lt;IntrBkSttlmAmt Ccy="USD"&gt;92500.00&lt;/IntrBkSttlmAmt&gt;
      &lt;Dbtr&gt;
        &lt;Nm&gt;Harbour Freight Logistics Ltd&lt;/Nm&gt;
        &lt;PstlAdr&gt;
          &lt;AdrLine&gt;Unit 7, Canary Wharf Business Park&lt;/AdrLine&gt;
          &lt;AdrLine&gt;London E14 5AB, United Kingdom&lt;/AdrLine&gt;
        &lt;/PstlAdr&gt;
      &lt;/Dbtr&gt;
      &lt;Cdtr&gt;
        &lt;Nm&gt;Pacific Rim Trading Co&lt;/Nm&gt;
        &lt;PstlAdr&gt;
          &lt;AdrLine&gt;Level 22, One Raffles Quay, North Tower, Marina Bay Financial Centre&lt;/AdrLine&gt;
          &lt;AdrLine&gt;Raffles Place, Downtown Core, Central Business District, Singapore 048583&lt;/AdrLine&gt;
          &lt;AdrLine&gt;Republic of Singapore&lt;/AdrLine&gt;
          &lt;Ctry&gt;SG&lt;/Ctry&gt;
        &lt;/PstlAdr&gt;
      &lt;/Cdtr&gt;
      &lt;UltmtCdtr&gt;
        &lt;Nm&gt;Lombardia Componenti SpA&lt;/Nm&gt;
        &lt;PstlAdr&gt;
          &lt;StrtNm&gt;Via Roma&lt;/StrtNm&gt;
          &lt;BldgNb&gt;12&lt;/BldgNb&gt;
          &lt;PstCd&gt;20121&lt;/PstCd&gt;
          &lt;TwnNm&gt;Milano&lt;/TwnNm&gt;
          &lt;AdrLine&gt;Via Roma 12, 20121 Milano&lt;/AdrLine&gt;
          &lt;Ctry&gt;ITA&lt;/Ctry&gt;
        &lt;/PstlAdr&gt;
      &lt;/UltmtCdtr&gt;
      &lt;CdtrAgt&gt;
        &lt;FinInstnId&gt;
          &lt;BICFI&gt;BCGECHGGXXX&lt;/BICFI&gt;
          &lt;PstlAdr&gt;
            &lt;Dept&gt;Treasury &amp;amp; Payments&lt;/Dept&gt;
            &lt;StrtNm&gt;Rue du Commerce 17&lt;/StrtNm&gt;
            &lt;PstCd&gt;1204&lt;/PstCd&gt;
            &lt;TwnNm&gt;Gen&amp;#232;ve&lt;/TwnNm&gt;
          &lt;/PstlAdr&gt;
        &lt;/FinInstnId&gt;
      &lt;/CdtrAgt&gt;
    &lt;/CdtTrfTxInf&gt;
  &lt;/FIToFICstmrCdtTrf&gt;
&lt;/Document&gt;</textarea>
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
<div id="out" aria-live="polite"></div>
<div id="paid"><strong>Free here:</strong> Names every ISO 20022 postal-address block your file sends that CBPR+ will not accept, with the line number and the rule behind it. <strong>In the editor:</strong> Exports a dated CBPR+ address audit file (CSV and Markdown) covering every message in the workspace, with the rule citation per finding, to hand to your correspondent bank or auditor. — that part asks for a licence key.
<p class="buy"><a href="https://getreadystack.com/api/buy/cl/polar_cl_hvlxO2MoABOcEHmAOJCtxxdriZukvoDX08sKM2VvzGU">Get the full version - export the dated CBPR+ address audit - $29</a></p>
<p class="terms">$29 once &middot; one licence key per person or CI seat &middot; A correspondent bank charges $15 to $40 to repair one payment by hand; this reads the message before you send it.</p></div>
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
</div>
<script>var CBPR_RULES = [
  {"id": "unstructured_only", "sev": "error", "title": "Address is fully unstructured", "msg": "PstlAdr has AdrLine only - no TwnNm and no Ctry. A fully unstructured address is the one shape CBPR+ removes; every agent on the route has to repair it by hand.", "cite": "SWIFT CBPR+ Usage Guidelines, PostalAddress24 - fully unstructured addresses withdrawn at the SR 2026 cutover (deferred 2026-08-27, revised timetable due by December 2026)."},
  {"id": "no_country", "sev": "error", "title": "Ctry missing", "msg": "PstlAdr has structured fields but no \u003cCtry\u003e. Country is mandatory in both the structured and the hybrid address option.", "cite": "ISO 20022 PostalAddress24 - Ctry mandatory for in-scope agents and parties under CBPR+."},
  {"id": "no_town", "sev": "error", "title": "TwnNm missing in a hybrid address", "msg": "PstlAdr mixes AdrLine with structured fields but has no \u003cTwnNm\u003e. Town and Country are the minimum a hybrid address must populate.", "cite": "SWIFT CBPR+ hybrid postal address, live since 2025-11-22 - TwnNm plus Ctry required at minimum."},
  {"id": "dup_in_adrline", "sev": "error", "title": "Structured value repeated inside AdrLine", "msg": "A value that already sits in a dedicated element is repeated inside an AdrLine. That is not a compliant hybrid address, it is malformed, and it may be rejected rather than repaired.", "cite": "SWIFT CBPR+ hybrid rule - if a component has a dedicated structured field it must go there and must not also appear in AdrLine."},
  {"id": "adrline_max2", "sev": "error", "title": "More than two AdrLine occurrences", "msg": "The hybrid postal address option allows at most two AdrLine occurrences. Extra lines are dropped or the message is rejected.", "cite": "SWIFT CBPR+ Usage Guidelines - AdrLine limited to 2 occurrences in the hybrid option."},
  {"id": "ctry_code", "sev": "error", "title": "Ctry is not an ISO 3166-1 alpha-2 code", "msg": "\u003cCtry\u003e must be exactly two upper-case letters. A country name or a three-letter code fails schema validation before the payment ever leaves.", "cite": "ISO 20022 CountryCode - pattern [A-Z]{2}, ISO 3166-1 alpha-2."},
  {"id": "adrline_70", "sev": "warn", "title": "AdrLine longer than 70 characters", "msg": "AdrLine is Max70Text. Anything past character 70 is truncated on the wire, and a truncated beneficiary address is a sanctions-screening hit waiting to happen.", "cite": "ISO 20022 Max70Text - AdrLine maximum length 70."},
  {"id": "charset", "sev": "warn", "title": "Character outside the CBPR+ character set", "msg": "An address field carries a character outside the permitted SWIFT set (letters, digits and / - ? : ( ) . , ' + space). Ampersands and accented letters are the usual cause of a NAK or a silent substitution.", "cite": "SWIFT CBPR+ character set restriction on ISO 20022 text elements."},
  {"id": "bldgnb_in_strtnm", "sev": "warn", "title": "House number buried in StrtNm", "msg": "StrtNm carries the house number and no \u003cBldgNb\u003e is present. The structured option has a dedicated element for it; leaving it in the street name is what makes address matching fail downstream.", "cite": "ISO 20022 PostalAddress24 - BldgNb is the dedicated element for the building number."}
]
;</script>
<script>/* CBPR+ Structured Address Lint - one brain, used by the VS Code extension and by the free web page. */
(function (root, factory) {
  var RULES = (typeof module !== 'undefined' && module.exports)
    ? require('./rules.json')
    : root.CBPR_RULES;
  var api = factory(RULES);
  if (typeof module !== 'undefined' && module.exports) { module.exports = api; }
  root.CBPRENGINE = api;
})(typeof globalThis !== 'undefined' ? globalThis : this, function (RULES) {

  var RULE_BY_ID = {};
  (RULES || []).forEach(function (r) { RULE_BY_ID[r.id] = r; });

  /* Elements that live inside <PstlAdr> in ISO 20022 PostalAddress24. */
  var ADDR_TAGS = ['Dept', 'SubDept', 'StrtNm', 'BldgNb', 'BldgNm', 'Flr', 'Room',
                   'PstBx', 'PstCd', 'TwnNm', 'TwnLctnNm', 'DstrctNm',
                   'CtrySubDvsn', 'Ctry', 'AdrLine'];

  /* Party elements a CBPR+ address hangs off, nearest one above the block names the finding. */
  var OWNERS = ['Dbtr', 'Cdtr', 'UltmtDbtr', 'UltmtCdtr', 'InitgPty', 'DbtrAgt', 'CdtrAgt',
                'IntrmyAgt1', 'IntrmyAgt2', 'IntrmyAgt3', 'InstgAgt', 'InstdAgt', 'FinInstnId'];

  /* The SWIFT character set CBPR+ keeps for text elements. */
  var OK_CHARS = /^[A-Za-z0-9\/\-\?:\(\)\.,'\+ ]*$/;

  function decode(s) {
    return String(s)
      .replace(/&lt;/g, '<').replace(/&gt;/g, '>')
      .replace(/&quot;/g, '"').replace(/&apos;/g, "'")
      .replace(/&#(\d+);/g, function (m, d) { return String.fromCharCode(parseInt(d, 10)); })
      .replace(/&amp;/g, '&');
  }

  function ownerOf(lines, idx) {
    for (var i = idx; i >= 0 && i > idx - 40; i--) {
      for (var k = 0; k < OWNERS.length; k++) {
        if (lines[i].indexOf('<' + OWNERS[k] + '>') !== -1) { return OWNERS[k]; }
      }
    }
    return 'party';
  }

  /* Cut the text into <PstlAdr> ... </PstlAdr> blocks, keeping real line numbers. */
  function addressBlocks(text) {
    var lines = String(text).split(/\r?\n/);
    var out = [], cur = null;
    for (var i = 0; i < lines.length; i++) {
      var L = lines[i];
      if (!cur && /<PstlAdr[\s>]/.test(L)) {
        cur = { line: i + 1, owner: ownerOf(lines, i), rows: [] };
      }
      if (cur) { cur.rows.push({ n: i + 1, t: L }); }
      if (cur && /<\/PstlAdr>/.test(L)) { out.push(cur); cur = null; }
    }
    if (cur) { out.push(cur); }
    return out;
  }

  /* Every address element in one block, with its own line number. */
  function fieldsOf(block) {
    var found = {};
    ADDR_TAGS.forEach(function (t) { found[t] = []; });
    block.rows.forEach(function (row) {
      ADDR_TAGS.forEach(function (tag) {
        var re = new RegExp('<' + tag + '>([^<]*)</' + tag + '>', 'g'), m;
        while ((m = re.exec(row.t)) !== null) {
          found[tag].push({ value: decode(m[1]).trim(), raw: m[1], line: row.n });
        }
      });
    });
    return found;
  }

  function one(id, line, where, detail) {
    var r = RULE_BY_ID[id] || { sev: 'error', msg: id, title: id };
    return {
      check: id,
      sev: r.sev,
      line: line,
      msg: where + ': ' + r.title + (detail ? ' (' + detail + ')' : '') + ' - ' + r.msg
    };
  }

  function check(text, opts) {
    opts = opts || {};
    var findings = [];
    addressBlocks(text).forEach(function (b) {
      var f = fieldsOf(b);
      var where = b.owner + ' PstlAdr line ' + b.line;
      var adr = f.AdrLine, twn = f.TwnNm[0], ctry = f.Ctry[0];
      var structured = ADDR_TAGS.some(function (t) {
        return t !== 'AdrLine' && f[t].length > 0;
      });

      if (adr.length > 0 && !twn && !ctry) {
        findings.push(one('unstructured_only', b.line, where,
          adr.length + ' AdrLine, no structured element'));
      } else {
        if (!ctry) { findings.push(one('no_country', b.line, where, null)); }
        if (adr.length > 0 && !twn) { findings.push(one('no_town', b.line, where, null)); }
      }

      if (ctry && !/^[A-Z]{2}$/.test(ctry.value)) {
        findings.push(one('ctry_code', ctry.line, where, ctry.value));
      }

      if (adr.length > 2) {
        findings.push(one('adrline_max2', adr[2].line, where, adr.length + ' occurrences'));
      }

      /* A component that owns a dedicated element must not be echoed in an AdrLine. */
      ['TwnNm', 'PstCd', 'StrtNm', 'BldgNb', 'CtrySubDvsn', 'DstrctNm'].forEach(function (tag) {
        f[tag].forEach(function (fld) {
          if (!fld.value) { return; }
          adr.forEach(function (a) {
            if (a.value.toLowerCase().indexOf(fld.value.toLowerCase()) !== -1) {
              findings.push(one('dup_in_adrline', a.line, where, tag + ' "' + fld.value + '"'));
            }
          });
        });
      });

      adr.forEach(function (a) {
        if (a.value.length > 70) {
          findings.push(one('adrline_70', a.line, where, a.value.length + ' chars'));
        }
      });

      ADDR_TAGS.forEach(function (tag) {
        f[tag].forEach(function (fld) {
          if (fld.value && !OK_CHARS.test(fld.value)) {
            var bad = fld.value.split('').filter(function (c) { return !OK_CHARS.test(c); });
            findings.push(one('charset', fld.line, where, tag + ' "' + bad.join('') + '"'));
          }
        });
      });

      if (f.StrtNm.length > 0 && f.BldgNb.length === 0) {
        f.StrtNm.forEach(function (s) {
          if (/(^\s*\d+[\s,])|([\s,]\d+\s*$)/.test(s.value)) {
            findings.push(one('bldgnb_in_strtnm', s.line, where, '"' + s.value + '"'));
          }
        });
      }
    });

    findings.sort(function (a, b) { return a.line - b.line; });
    if (opts.today) { findings.today = opts.today; }
    return { findings: findings };
  }

  return { engine: { check: check }, RULES: RULES, RULE_COUNT: (RULES || []).length };
});
</script>
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
'use strict';
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
function summaryLine(res) {
  const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
  return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
}
function toText(res, label) {
  const f = (res && res.findings) || [];
  const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
  f.forEach(function (x) { lines.push('  ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + '  ' + (x.line ? 'L' + x.line + '  ' : '') + (x.check || x.id || '') + '  ' + (x.msg || x.message || '')); });
  return lines.join('\n');
}
function toHtml(res) {
  const f = (res && res.findings) || [];
  if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
  const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
  return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
}
var CBPRREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
if (typeof module !== 'undefined' && module.exports) module.exports = CBPRREPORT;
else window.CBPRREPORT = CBPRREPORT;
</script>
<script>
(function(){
  var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
  today.value=new Date().toISOString().slice(0,10);
  function run(){ try { var res=window.CBPRENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.CBPRREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
  go.onclick=run; if (src.value.trim()) run();
})();
</script>


<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://marketplace.visualstudio.com/items?itemName=ReadyStack.cbpr-address-lint" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'cbpr-address-lint',src:'mp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/cbpr-address-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'cbpr-address-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/cbpr-address-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'cbpr-address-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://www.npmjs.com/package/@readystack/cbpr-address-lint" rel="noopener" data-yj-install-door="mcp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'cbpr-address-lint',src:'mcp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">MCP server (npx)</a><a href="https://hub.docker.com/r/getreadystack/cbpr-address-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'cbpr-address-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">ext install ReadyStack.cbpr-address-lint
npx @readystack/cbpr-address-lint &lt;file&gt;
npx @readystack/cbpr-address-lint --mcp</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 9 rules CBPR+ Structured Address Lint checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"cbpr-address-lint",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>

<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Find the ISO 20022 postal addresses your correspondent bank will repair by hand, before you send the message</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A correspondent bank charges $15 to $40 to repair one cross-border payment by hand; the average fee for a rejected or repaired payment is reported at about $12.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_hvlxO2MoABOcEHmAOJCtxxdriZukvoDX08sKM2VvzGU" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>

<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-20">Updated 2026-09-20</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-20","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku142540_result_card.jpg" alt="CBPR+ Structured Address Lint" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>Six of the nine CBPR+ postal-address rules are the ones that get a cross-border payment repaired by hand, and a single sample pacs.008 in this repository breaks all six - 13 findings, 9 of them errors, across all 4 party address blocks in one message. If you are a payments-integration developer at a bank, a PSP or a treasury software vendor, that file is the one your mapping code generates.</p>
<p>Here is the shape that does it:</p>
<p>&lt;PstlAdr&gt; &lt;AdrLine&gt;Unit 7, Canary Wharf Business Park&lt;/AdrLine&gt; &lt;AdrLine&gt;London E14 5AB, United Kingdom&lt;/AdrLine&gt; &lt;/PstlAdr&gt;</p>
<p>That is a legal ISO 20022 postal address and it validates against the schema. It is also the one address shape CBPR+ is removing, and every agent on the route has to take it apart by hand.</p>
<h3>The dates, and why your assistant gets them wrong</h3>
<p>On 2025-11-22 the hybrid postal address option went live in CBPR+. Town and country go in dedicated elements, at most two AdrLine occurrences remain, and - this is the part that surprises people - a component that owns a structured element must not also be echoed in an address line. Removal of fully unstructured addresses was set for 2026-11-14. Then, on 2026-08-27, Swift deferred the payments-related Standards Release 2026 changes, including that removal, and said a revised timetable would be announced by December 2026.</p>
<p>So the cliff moved and the hybrid rules did not. A model trained before August 2026 tells you the November 2026 date is firm; a model trained after it tells you the whole thing is postponed. Both answers get you a repaired payment, because a malformed hybrid is rejected today.</p>
<h3>What a malformed hybrid looks like</h3>
<p>&lt;StrtNm&gt;Via Roma&lt;/StrtNm&gt; &lt;BldgNb&gt;12&lt;/BldgNb&gt; &lt;PstCd&gt;20121&lt;/PstCd&gt; &lt;TwnNm&gt;Milano&lt;/TwnNm&gt; &lt;AdrLine&gt;Via Roma 12, 20121 Milano&lt;/AdrLine&gt; &lt;Ctry&gt;ITA&lt;/Ctry&gt;</p>
<p>Run the linter over that block and it returns 5 errors: four dup_in_adrline, one for each of street, building number, postcode and town repeated inside the address line, plus one ctry_code because ITA is three letters and CountryCode is ISO 3166-1 alpha-2. Nothing here is a typo - somebody kept the legacy free-text address alongside the new structured one.</p>
<p>A third block - a Swiss agent address with no Ctry, an ampersand in Dept and the house number left inside StrtNm - returns 4 findings. Same tool, three different party blocks, three different answers: 1, 5 and 4.</p>
<h3>The 9 rules</h3>
<p>Six errors: unstructured_only, no_country, no_town, dup_in_adrline, adrline_max2, ctry_code. Three warnings: adrline_70 past Max70Text, charset for a character outside the permitted SWIFT set, and bldgnb_in_strtnm for a house number with no dedicated element.</p>
<h3>What it costs to not run it</h3>
<p>A correspondent bank charges $15 to $40 to repair one cross-border payment by hand, and the average fee for a rejected or repaired payment is reported at about $12. That is per payment. A bad address template does not produce one bad payment, it produces every payment it generates until somebody notices.</p>
<h3>Free, and where the key starts</h3>
<p>Free, with no key: open any pacs.008, pacs.009 or pain.001 and get every failing address block named, on the line where it fails, with the rule behind it. That is the whole job for one file and it finishes there.</p>
<p>The paid layer sits on a different axis - ownership. It exports a dated CBPR+ address audit, CSV and Markdown, for every message in the workspace, with the rule citation per finding, so the evidence leaves the editor as a file you can hand to your bank or your auditor. The same engine runs free in the browser, with nothing uploaded.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku142540_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku142540_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does CBPR+ Structured Address Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads the PstlAdr blocks in your ISO 20022 XML - pacs.008, pacs.009, pain.001 - and flags each one that breaks a CBPR+ postal-address rule, on the line where it breaks, with the rule behind it. 9 rules, 6 of them errors. It runs on the file in your editor and, with a key, across the whole workspace into a dated audit file.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Payments-integration developers and ISO 20022 migration engineers at banks, PSPs and treasury software vendors - the people who write the mapping code or review what a code assistant generated. If you own a pacs.008 template, an ERP payment export, or the address mapping from a customer master file, this is your file.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why doesn&#x27;t schema validation catch this?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Because a malformed hybrid address is schema-valid. XSD checks types and lengths, so a block that repeats Milano in both TwnNm and an AdrLine passes. The CBPR+ usage guidelines sit above the schema: hybrid rules live since 2025-11-22, and the unstructured cutover deferred 2026-08-27. A general chatbot gets those two dates wrong in both directions.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence key?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free, with no key: lint the file open in your editor against all 9 rules and see every failing address block with its line number. That finishes the job for one file. The paid layer is ownership - a dated CSV and Markdown audit of every message in the workspace, written to disk as evidence you can hand over. $29 once.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would this cost without the tool?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A correspondent bank charges $15 to $40 to repair one cross-border payment by hand, and the average fee for a rejected or repaired payment is reported at about $12. Those are per payment, and a bad address template repeats on every payment it generates. The extension is $29 once, and the file check is free.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. CBPR+ Structured Address Lint checks the file you open against 9 rules, each naming its legal or official basis, from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does CBPR+ Structured Address Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads the PstlAdr blocks in your ISO 20022 XML - pacs.008, pacs.009, pain.001 - and flags each one that breaks a CBPR+ postal-address rule, on the line where it breaks, with the rule behind it. 9 rules, 6 of them errors. It runs on the file in your editor and, with a key, across the whole workspace into a dated audit file."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Payments-integration developers and ISO 20022 migration engineers at banks, PSPs and treasury software vendors - the people who write the mapping code or review what a code assistant generated. If you own a pacs.008 template, an ERP payment export, or the address mapping from a customer master file, this is your file."}}, {"@type": "Question", "name": "Why doesn't schema validation catch this?", "acceptedAnswer": {"@type": "Answer", "text": "Because a malformed hybrid address is schema-valid. XSD checks types and lengths, so a block that repeats Milano in both TwnNm and an AdrLine passes. The CBPR+ usage guidelines sit above the schema: hybrid rules live since 2025-11-22, and the unstructured cutover deferred 2026-08-27. A general chatbot gets those two dates wrong in both directions."}}, {"@type": "Question", "name": "What is free and what needs a licence key?", "acceptedAnswer": {"@type": "Answer", "text": "Free, with no key: lint the file open in your editor against all 9 rules and see every failing address block with its line number. That finishes the job for one file. The paid layer is ownership - a dated CSV and Markdown audit of every message in the workspace, written to disk as evidence you can hand over. $29 once."}}, {"@type": "Question", "name": "What would this cost without the tool?", "acceptedAnswer": {"@type": "Answer", "text": "A correspondent bank charges $15 to $40 to repair one cross-border payment by hand, and the average fee for a rejected or repaired payment is reported at about $12. Those are per payment, and a bad address template repeats on every payment it generates. The extension is $29 once, and the file check is free."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. CBPR+ Structured Address Lint checks the file you open against 9 rules, each naming its legal or official basis, from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:142540,slug:"cbpr-address-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/sepa-pain001-reject-lint"><span class="yj-rel-t">SEPA pain.001 Reject Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/mcp-2026-migration-lint"><span class="yj-rel-t">MCP 2026 Migration Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/maven-central-publish-gate"><span class="yj-rel-t">Maven Central Publish Gate</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/personal-data-map-dsar-audit"><span class="yj-rel-t">Personal Data Map: find every column a GDPR subject access request has to reac</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pg-migration-lock-lint"><span class="yj-rel-t">Postgres Migration Lock Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/soup-list-lint"><span class="yj-rel-t">SOUP List Lint (IEC 62304)</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body>
</html>