Part of a Data Solution
- Explore →
Postal Codes Solution
Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.
Premium
You're viewing a free sample
Get the complete dataset — all rows and files — delivered instantly after checkout, with lifetime access to the latest version.
- Secure checkout via Stripe
- Instant download after payment
- Lifetime access to the latest version
API Access
Access dataset files directly from scripts, code, or AI agents.
Browse dataset files
API Access
Access dataset files directly from scripts, code, or AI agents.
Each file has a stable URL (r-link) that you can use directly in scripts, apps, or AI agents. These URLs are permanent and safe to hardcode.
Start with these files — they give you everything you need to understand and access the dataset.
- 1. Fetch datapackage.yaml to inspect schema and resources
- 2. Download data resources listed in datapackage.yaml
- 3. Read README.md for full context
Data Files
postal-codes-kw-sample
| Field | Type | Description | Title |
|---|---|---|---|
| country_code | string | ISO 3166-1 alpha-2 code for the country - always KW. | Country Code |
| postal_code | string | Postal code (2-6 digits). Read as text. A code can appear on more than one row. | Postal Code |
| place_name | string | Area or post office name (English), as spelled by the ministry. | Place Name |
| admin_name1 | string | Governorate name. | Administrative Name 1 |
| admin_code1 | string | ISO 3166-2:KW governorate code (KU, AH, HA, FA, MU, JA). | Administrative Code 1 |
| admin_name2 | string | Area (same as place_name). | Administrative Name 2 |
| admin_code2 | string | Empty - the source has no code at this level. | Administrative Code 2 |
| admin_name3 | string | Unit the code covers: 'PO Box a-b' or 'Block n'. | Administrative Name 3 |
| admin_code3 | string | Empty - the source has no code at this level. | Administrative Code 3 |
| latitude | string | Empty - the source tables carry no coordinates. | Latitude |
| longitude | string | Empty - the source tables carry no coordinates. | Longitude |
| accuracy | string | Empty. | Accuracy |
| alternative_city_name | string | Area or post office name in Arabic. | Alternative City Name |
About this dataset
Kuwait (KW): migration notes
Internal record of the SST migration. This is a dated record (2026-10-09) and is not shipped in the zip.
- Issue: none for the SST conversion (the beads database was unavailable locally); the producer port had none either.
- Producer:
scripts/produce.py(custom), ported 2026-10-09. The dataset stays frozen (nopipeline:): the licence is unresolved, so nothing runs the producer automatically. Run it by hand. - Parity:
parity.pyonly runs the frozen check on a dataset with nopipeline:, so the comparison was done by hand (see below).
History
-
P3 migrated
kwas a no-data dataset (data_available: false, header-only CSV). -
mainthen gained7f56647(2026-10-08): Kuwait rebuilt from the Ministry of Communications tables and sold as premium tier B (premium_source_key: kw/kw.zip). That commit changed only metadata (datapackage.yml,README.md,.licensing-notes.md); no builder script was committed. -
The branch merged
maintaking itsdatasets/kwas-is (1a88856), and this commit converts that descriptor to the SST shape. -
a811e1f(2026-10-08) committed the builder:scrape_moc.py(Playwright replay of the page's server action) andbuild_kw.py, pluspackage_kw.pyandpublish_r2.py. -
2026-10-09: ported to
scripts/produce.py+test_produce.py; the old scripts were removed (they're ina811e1f).
What was carried over
- Description, sources, tier B and
kw/kw.zipsource key, and the field descriptions, taken from7f56647. Nothing about pricing was decided here. ATTRIBUTION.txtcopied verbatim from the live zip.- No
licensesentry: the licence is unresolved and the owner chose to omit it (see.licensing-notes.md). Frozen datasets may omit it. - Schema stays all-string with no primaryKey (no producer owns it). For a future producer:
(postal_code, place_name, admin_name3)is unique in the live CSV, andpostal_codealone is not.
Checked against R2 (2026-10-09, read only)
- Premium bucket
kw/kw.zip(uploaded 2026-10-08) holdskw.csvwith 5,656 rows, 5,586 distinct codes, all 6 governorates, and no coordinates. - Public
postal.datahub.io/kw/kw.csvis the first 100 rows of that CSV (byte-exact prefix).
Producer port (2026-10-09)
- Fetching without a browser. The page's server action works over plain HTTP. The producer finds the action id the way the browser does, from the page's
/_next/static/chunks/*.js(createServerReference("<id>", …, "requestPayloadCollection")); the id changes with each site deploy. It sends the same request body asscrape_moc.py(same query, no sort), but with page size 1000 instead of 10, so a full run takes 14 table requests (1 s apart) instead of about 1,130. The server accepts 1000. - TLS. moc.gov.kw doesn't send its intermediate certificate. Python's urllib, unlike curl and browsers, doesn't fetch it via AIA. The producer downloads the DigiCert intermediate from the certificate's AIA URL and adds it to the default context, with partial chains off, so the chain must still end at a trusted root.
- Paging guard. An unsorted listing could skip or repeat rows across pages, so the producer fails unless each table yields exactly
totalDocsdistinct ids. - Transforms. All of
build_kw.pyis ported unchanged:$1:reference resolution, the ISO 3166-2:KW substring crosswalk, the PO Box / Block units, Arabic names matched by id, duplicates collapsed on (code, governorate, area, unit), and the sort.write_outputsthen reorders rows within each postal code by bytes (canonical_order). Its checks becameProducerErrors: every code is 2-6 digits, all 6 governorates are present, every governorate is mapped, and every relation resolves. The old warnings (codes on several rows, PO Box gaps/overlaps, non-integer blocks, records missing an Arabic counterpart) describe the source and weren't ported. - Comparison with live (by hand). There's no
.env.prodin this checkout, so the premium zip wasn't read. Fresh output, 2026-10-09: 5,656 rows, 5,586 distinct codes, 6 governorates and no coordinates, matching the counts recorded from the live zip above. The public sample (postal.datahub.io/kw/kw.csv, the zip CSV's first 100 rows) is a byte-exact prefix of the fresh CSV.
Decisions
| Decision | By | Basis |
|---|---|---|
Re-migrate kw on top of main's version | User, 2026-10-09 | PR #37 conflict with 7f56647 |
| Frozen (no producer) | Standing rule (user, 2026-10-03) | No builder scripts in the repo to port (superseded by the next two rows) |
Port the a811e1f builder to produce.py | User, 2026-10-09 | The builder is now in the repo |
Stay frozen (no pipeline:) after the port | User, 2026-10-09 | Licence unresolved; SST §9 says the frozen rule is the licence enforcement |
| Plain HTTP instead of Playwright; page size 1000 | Port choice, 2026-10-09 | Same source and request; no browser dependency; ~80x fewer requests |
Open questions
- Resolved: the builder was committed in
a811e1fand ported. Unfreezing (addingpipeline:) waits on the licence decision. - pending: Byte-for-byte check of the fresh CSV against the premium zip
kw/kw.ziponce.env.prodis available. - pending: The retrieval date differs. The datapackage and README say 2026-10-08; the zip's
ATTRIBUTION.txtanddatapackage.jsonsay 2026-10-06.
Provenance
Written 2026-10-09 from 7f56647, the live zip and sample, and the merge session. Producer-port sections added 2026-10-09 from a live run of produce.py.