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
- Creative Commons Attribution 4.0 International license
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-za-sample
| Field | Type | Description | Constraints | Title |
|---|---|---|---|---|
| country_code | string | ISO 3166-1 alpha-2 -- always ZA | Country Code | |
| postal_code | string | South African postal code (4 digits) | { "pattern": "^\\d{4}$" } | Postal Code |
| place_name | string | Locality/place name as GeoNames' postal export records it | Place Name | |
| admin_name1 | string | Province -- 9/9 covered, resolved via a coordinate-based join against GeoNames' own gazetteer (not an official admin register), see ATTRIBUTION.txt | Administrative Name 1 | |
| admin_code1 | string | ISO 3166-2:ZA code | Administrative Code 1 | |
| admin_name2 | string | District/metro municipality -- 52/52 covered, same coordinate-based join | Administrative Name 2 | |
| admin_code2 | string | GeoNames' own admin2 code (not an independently verified official code) | Administrative Code 2 | |
| admin_name3 | string | Not populated -- no sellable source reaches this tier | Administrative Name 3 | |
| admin_code3 | string | Not populated | Administrative Code 3 | |
| latitude | number | GeoNames postal-export latitude (WGS84) | Latitude | |
| longitude | number | GeoNames postal-export longitude (WGS84) | Longitude | |
| accuracy | string | AREA throughout -- coarse city/town-level point, shared across all codes in that place | Accuracy | |
| alternative_city_name | string | Not populated in this release | Alternative City Name |
Download
Download sample CSVAbout
- Last updated
- 6 October 2026
- Total rows
- 100
- Format
- CSV
- File size
- 10.4 kB
About this dataset
South Africa (ZA): migration notes
Internal record of the P5 migration from the old scripts to the producer: the discrepancies found, their causes, and who decided what. This is a dated record, so the numbers are as of the migration and not kept current. It is not shipped in the zip.
- Issue: pc-28e.7.57 (closed 2026-10-02)
- Commit:
bf3fe72(worktree commit6660d70, same content), landed in batch 3 - Parity verdict:
explained(row_orderonly); signed off under the standing rule - Producer:
custom, refresh disabled
Sources
| Input | URL | Notes |
|---|---|---|
| GeoNames postal export | https://download.geonames.org/export/zip/ZA.zip | Carries no admin fields for ZA |
| GeoNames gazetteer dump | https://download.geonames.org/export/dump/ZA.zip | Populated places (class P) with admin1/admin2 |
| GeoNames admin2 codes | https://download.geonames.org/export/dump/admin2Codes.txt | District/metro names. Fetched by the producer but not listed in the descriptor's sources |
The old builder read all three from local files; the producer now fetches them. SAPO, AfriGIS, opendb.co.za and other candidates were ruled out earlier (.licensing-notes.md, 2026-08-28/29).
Parity against the live zip (2026-10-02)
Rows: 3,920 live and 3,920 fresh, none only on one side. 0 changed cells. The only class is row_order: rows sharing a postal code swapped (e.g. 0008 Atteridgeville / Pretoria, 0017 Doornpoort, 0029 Philip Nel Park). Sorted and with line endings normalised, the two files are byte-identical. The live CSV is CRLF, the fresh one LF.
The informational sample check against https://postal.datahub.io/za/za.csv came back unexplained (leading_zero_restored 100, unclassified 584). It is outside the gate and was not traced.
Decisions
| Decision | By | Basis |
|---|---|---|
Accept the row_order verdict and land | Standing rule (row_order/CRLF-only, user, 2026-10-02) | Equal rows, 0 changed cells |
Keep the existing accuracy description, not the standard GeoNames wording | Agent; the orchestrator agreed (session 2479b1c9-…) | The column is the constant AREA, not a GeoNames code. The agent asked for a decision; it was not put to the user |
Replace the licence_status.decision sentence with "CC BY 4.0, which is compatible with this commercial product" | Agent | The agent asked for the wording to be checked; no answer recorded |
| Remove the row and distinct-code counts; keep 9/9 provinces and 52/52 municipalities | Orchestrator instruction (the user's README counts rule) | |
| No row-count assert | Orchestrator instruction | Brief: structural checks only |
Transforms carried over
From build_postal_codes_product.py (2026-08-29):
- Province and district/metro municipality joined from the dump's populated places that have an admin2 code: exact name/asciiname match, nearest by haversine; if there's no match or it is >50 km away, the nearest of all candidates; nothing within 100 km is an error. Ties keep dump order.
- GeoNames admin1 number → ISO 3166-2:ZA and province name via the 9-province crosswalk;
admin_name2from admin2Codes.txt;admin_code2is GeoNames' own code (e.g.TSH,DC32). - Latitude/longitude rounded to 5 dp and written as Python floats (
-30→-30.0); accuracyAREA; admin3 andalternative_city_nameempty; stable sort by postal_code. - The old asserts are now
ProducerErrors: ZA row shape, 4-digit postal code, unique (postal_code, place_name), known admin1, admin2 present in admin2Codes.txt, all 9 provinces present, nothing unresolved.
Open questions
- Resolved (user, 2026-10-05, pc-28e.7.59): the licence wording is left to pc-hfz, which settles one wording across datasets.
- Resolved (2026-10-05, pc-28e.7.60): added admin2Codes.txt to
sources. Was: Missing source entry:datapackage.yamlsourcesdoesn't list admin2Codes.txt, though the producer fetches it (ua's does). ATTRIBUTION.txtstill carries old join counts (e.g. "1041 rows" on the fallback path); it belongs to the pc-hfz sweep.
Provenance
Reconstructed 2026-10-05 from the agent transcript 2479b1c9-c4dd-47e5-be82-34ccf8d49a80/subagents/agent-a0218d6b553f73ab9.jsonl, the orchestrator session 2479b1c9-… (also checked 068ca403-… and 803a95aa-…: no za decisions), the commit message, the bd close reason and docs/parity/p5.md.