Postal Codes Dataset for South Africa, ZA

508
Updated:
Files:1
Size:384 kB
Rows:3,920
Formats:csv
License:CC-BY-4.0

Postal Codes Dataset for South Africa, ZA including name of the city, town, or place, various administrative divisions and alternative city names.

Part of a Data Solution

  • Postal Codes Solution

    Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.

    Explore →

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
20% off
$49.90$39.92
one-time payment

API Access

Access dataset files directly from scripts, code, or AI agents.

Browse dataset files
Dataset Files

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.

/logistics/postal-codes-za/
https://datahub.io/logistics/postal-codes-za/_r/-/.licensing-notes.md
https://datahub.io/logistics/postal-codes-za/_r/-/.migration-notes.md
https://datahub.io/logistics/postal-codes-za/_r/-/ATTRIBUTION.txt
https://datahub.io/logistics/postal-codes-za/_r/-/README.md
https://datahub.io/logistics/postal-codes-za/_r/-/datapackage.yaml
Key Files

Start with these files — they give you everything you need to understand and access the dataset.

datapackage.yaml— metadata & schema
https://datahub.io/logistics/postal-codes-za/_r/-/datapackage.yaml
README.md— documentation
https://datahub.io/logistics/postal-codes-za/_r/-/README.md
Typical Usage
  1. 1. Fetch datapackage.yaml to inspect schema and resources
  2. 2. Download data resources listed in datapackage.yaml
  3. 3. Read README.md for full context

Data Files

postal-codes-za-sample


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 commit 6660d70, same content), landed in batch 3
  • Parity verdict: explained (row_order only); signed off under the standing rule
  • Producer: custom, refresh disabled

Sources

InputURLNotes
GeoNames postal exporthttps://download.geonames.org/export/zip/ZA.zipCarries no admin fields for ZA
GeoNames gazetteer dumphttps://download.geonames.org/export/dump/ZA.zipPopulated places (class P) with admin1/admin2
GeoNames admin2 codeshttps://download.geonames.org/export/dump/admin2Codes.txtDistrict/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

DecisionByBasis
Accept the row_order verdict and landStanding rule (row_order/CRLF-only, user, 2026-10-02)Equal rows, 0 changed cells
Keep the existing accuracy description, not the standard GeoNames wordingAgent; 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"AgentThe 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 municipalitiesOrchestrator instruction (the user's README counts rule)
No row-count assertOrchestrator instructionBrief: 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_name2 from admin2Codes.txt; admin_code2 is GeoNames' own code (e.g. TSH, DC32).
  • Latitude/longitude rounded to 5 dp and written as Python floats (-30 → -30.0); accuracy AREA; admin3 and alternative_city_name empty; 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.yaml sources doesn't list admin2Codes.txt, though the producer fetches it (ua's does).
  • ATTRIBUTION.txt still 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.