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 — postal layer (GeoNames) 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-id-sample
| Field | Type | Description | Constraints | Title |
|---|---|---|---|---|
| country_code | string | ISO 3166-1 alpha-2 country code — always ID | { "pattern": "^ID$", "required": true } | Country Code |
| postal_code | string | Five-digit Indonesian kodepos. Leading zeros are significant: read via this descriptor or pass dtype=str. | { "pattern": "^\\d{5}$", "required": true } | Postal Code |
| place_name | string | Desa (village) or Kelurahan (urban ward) — the tier kodepos are assigned at. Where the administrative columns are empty this is the postal source's own place name, unverified against the official register. | { "required": true } | Place Name |
| admin_name1 | string | Provinsi (province). Empty on rows the postal source could not be tied to an official village — empty means unknown, and is never filled with a placeholder. | Administrative Name 1 | |
| admin_code1 | string | ISO 3166-2:ID subdivision code, ID- prefix stripped | Administrative Code 1 | |
| admin_name2 | string | Kabupaten (regency) or Kota (city) | Administrative Name 2 | |
| admin_code2 | string | Kemendagri regency/city code (NN.NN) | { "pattern": "^\\d{2}\\.\\d{2}$" } | Administrative Code 2 |
| admin_name3 | string | Kecamatan (district) | Administrative Name 3 | |
| admin_code3 | string | Kemendagri district code (NN.NN.NN) | { "pattern": "^\\d{2}\\.\\d{2}\\.\\d{2}$" } | Administrative Code 3 |
| latitude | number | WGS84 latitude, decimal degrees, max 5 dp | Latitude | |
| longitude | number | WGS84 longitude, decimal degrees, max 5 dp | Longitude | |
| accuracy | string | GeoNames accuracy of latitude/longitude. GeoNames documents 1=estimated, 4=geonameid, 6=centroid of addresses or shape; other values (e.g. 3) occur upstream without documentation. Empty where GeoNames gives none. | Accuracy | |
| alternative_city_name | string | Pipe-separated source spellings of the village name that differ from the official Kemendagri spelling | Alternative City Name |
Download
Download sample CSVAbout
- Last updated
- 6 October 2026
- Total rows
- 100
- Format
- CSV
- File size
- 9.72 kB
About this dataset
Indonesia (ID): 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.25 (closed 2026-10-05)
- Commit:
537bc2d, landed in batch 6 - Parity verdict:
unexplained(the gate blocks on any unclassified cell); accepted as upstream drift - Producer:
custom, refresh disabled
Sources
| Input | URL | Notes |
|---|---|---|
| GeoNames postal export | https://download.geonames.org/export/zip/ID.zip | |
| Kepmendagri No. 300.2.2-2430/2025 admin codes | https://raw.githubusercontent.com/cahyadsn/wilayah/master/db/wilayah.sql | No versioned download, so master counts as the latest release |
The old builder also downloaded cahyadsn/wilayah_kodepos (wilayah_kodepos.json). It is not fetched any more: it only fed the cross-check audit and never reached the product, and its licence chain is unverified.
Parity against the live zip (2026-10-03)
Rows: 81,044 live and 81,044 fresh, none only on one side. 1 row changed (3 cells). Apart from that row the only difference was line endings (CRLF→LF).
| Key | Column | Live | Fresh |
|---|---|---|---|
| 22654 / 12.01.19 / Sialogo | latitude | 1.834 | 1.6714 |
| longitude | 98.6596 | 98.9266 | |
| accuracy | 4 | 3 |
Cause: GeoNames reordered its file (upstream drift).
- ID.txt has two rows for 22654 that resolve to the same village: "Sialogo" (1.834 / 98.6596 / 4) and "Sialogo (Sihalogo)" (1.6714 / 98.9266 / 3).
- The merge keeps the coordinate of whichever row comes first. That rule is ported unchanged from
build_postal.py. - In today's file "Sialogo (Sihalogo)" comes first (line 7412 vs 7417). The Wayback copy of ID.zip from 2025-10-07 has the opposite order (7406 vs 7410).
- Once sorted, both files hold the same 81,058 lines; 76,192 lines changed position. The exact August 2026 build input wasn't saved, so the Wayback copy is the closest evidence available.
Decisions
| Decision | By | Basis |
|---|---|---|
| Accept the Sialogo change | Standing rule (upstream drift traced to source, user, 2026-10-03) | Evidence above; recorded in the sign-off section of docs/parity/p5.md |
| Keep "first GeoNames row wins" in the merge | Agent: a faithful port | Changing it is a logic change, which needs sign-off. See open questions |
Drop the wilayah_kodepos.json input | Agent | Audit-only input with an unverified licence |
Don't port the audit side files (admin_coverage.csv, prefix_outliers.csv, crosscheck.csv) or run_qa.py / delivery_README_template.md | Agent | QA and packaging only, no product data |
Replace the placeholder sources ("Multiple sources") with the two real upstreams | Orchestrator instruction | pc-dky |
Transforms carried over (unchanged)
- wilayah.sql tuples parsed and tiered by how many dots the code has; names title-cased (DKI/DI and short acronyms kept,
Kab.→Kabupaten,Kota Adm.→Kota Administrasi). - GeoNames' own admin codes are discarded. Rows are tied to villages by folded name: unique name, then postal-code consensus, then 3-digit-prefix consensus (≥60%). There is no province step.
- One row per (postal code, village), first GeoNames row wins; other spellings go to
alternative_city_name. - ISO 3166-2:ID comes from the numeric province code, never the name.
- Unresolved rows are shipped once each, with empty admin and accuracy columns.
- Coordinates rounded to ≤5 dp; the original sort order is kept.
- The old asserts are now
ProducerErrors, plus new structural checks: every province has an ISO code and postal rows, admin codes nest, the primary key is unique.
Open questions
- Resolved (user, 2026-10-05, pc-28e.7.59): the merge now takes coordinates and accuracy from the first GeoNames row spelled exactly as the official village name, else the first row. Sialogo now matches live again. Parity after the change: 3 rows differ from live, each now taking the exact-spelling twin's coordinates (1–5 km apart): 94765 Arga Kencana (was Argakencana's), 91854 Rindingallo (was Rinding Allo's), 97128 Batu Merah (was Batumerah's).
- Resolved (user, 2026-10-05): the 3 changed rows are signed off.
.licensing-notes.mdandATTRIBUTION.txtstill contain counts; they are left for the end-of-epic sweep (pc-hfz).
Provenance
Reconstructed 2026-10-05 from the agent transcript 7df0c5be-a523-4080-87f9-6045a6a41515/subagents/agent-a6be74abc20bcd918.jsonl, the orchestrator session 7df0c5be-…, the commit message and the bd close reason.