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 (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-ph-sample
| Field | Type | Description | Constraints | Title |
|---|---|---|---|---|
| country_code | string | ISO 3166-1 alpha-2 country code — always PH | { "pattern": "^PH$", "required": true } | Country Code |
| postal_code | string | 4-digit Philippine ZIP code | { "pattern": "^\\d{4}$", "required": true } | Postal Code |
| place_name | string | City, municipality, barangay or post-office station name as supplied by the source | { "required": true } | Place Name |
| admin_name1 | string | Region (Rehiyon) — blank on institutional codes | Administrative Name 1 | |
| admin_code1 | string | ISO 3166-2:PH region code, PH- prefix stripped. There is no 04. Blank on institutional codes | { "pattern": "^(0[0-35-9]|1[0-5]|4[01])$" } | Administrative Code 1 |
| admin_name2 | string | Province; for the National Capital Region, the PSA district — blank on institutional codes | Administrative Name 2 | |
| admin_code2 | string | PSA PSGC 9-digit code for the province or NCR district | Administrative Code 2 | |
| admin_name3 | string | City or Municipality (LGU) that place_name belongs to, resolved against the PSA PSGC register | Administrative Name 3 | |
| admin_code3 | string | PSA PSGC 9-digit code for the city or municipality | Administrative Code 3 | |
| latitude | number | Latitude, decimal degrees (WGS84) | Latitude | |
| longitude | number | Longitude, decimal degrees (WGS84) | 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 | Local-language or historic name where the source supplied one genuinely different from place_name | Alternative City Name |
Download
Download sample CSVAbout
- Last updated
- 3 October 2026
- Total rows
- 100
- Format
- CSV
- File size
- 10.4 kB
About this dataset
Philippines (PH): 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.43 (closed 2026-10-03)
- Commit:
69801b0(worktree commit4806b0f, landed unchanged), batch 4; follow-up568cd10by the orchestrator (PSGC insources,rapidfuzzinrequirements-producers.txt) - Parity verdict:
unexplained(2 unclassified cells plus a duplicate key on both sides; the gate blocks on either); accepted - Producer:
custom, refresh disabled
Sources
| Input | URL | Notes |
|---|---|---|
| GeoNames postal export | https://download.geonames.org/export/zip/PH.zip | |
| GeoNames gazetteer dump | https://download.geonames.org/export/dump/PH.zip | Used for alternative_city_name |
| PSA PSGC register via the psgc.gitlab.io API | https://psgc.gitlab.io/api/provinces/, /cities-municipalities/, /barangays/ | Stable, undated URLs; the same API the old enrich_admin.py used |
- Live
ph.csvcarries cleaned names and dump alternate names, which come from the monthly generic GeoNames job (geonames_parse_to_R2.py), withbuild_base.py's fixes andenrich_admin.py's PSGC enrichment on top. Until 2026-08-19build_base.pyread a snapshot of the live R2 file (ph_r2_snapshot_2026-08-18.csv). After it was repointed to the raw GeoNames export, it would have shippedalternative_city_nameempty, because nothing reproduced the alternate-names join. - The producer folds in all three layers, so the GeoNames-job step (name cleaning + dump alternate names, the same rule as
scripts/producers/geonames.py) is back.
Parity against the live zip (2026-10-03)
Rows: 2,317 live and 2,317 fresh, none only on one side. 14 changed rows. All PSGC admin columns (admin_code2, admin_name3, admin_code3), all names and all ISO region codes match live exactly.
| Class | Cells | Examples | Cause |
|---|---|---|---|
float_suffix_dropped | 13 (6 latitude, 7 longitude) | 7021 Midsalip lat 8.0 → 8; 3521 Santa Praxedes lon 121.0 → 121; 5309 San Vicente 10.0/119.0 → 10/119 | The old pipeline went through pandas, which writes .0; the producer copies GeoNames' text. Same number |
unclassified, alternative_city_name | 2 | 6108 Himamaylan: empty → Khimamejlen; 8002 Digos: Digos City → empty | GeoNames dump drift. Today's entry 1711718 (Himamaylan) lists Khimamejlen,Химамейлен; entry 1714956 (Digos) lists Digos first, which equals place_name and is dropped, so Digos City no longer wins |
Duplicate key (both sides): 1412 Isla de Cocomo / Isla De Cocomo. GeoNames has both rows, differing only in case. parity.py casefolds keys, so it counts them as a duplicate; the exact primary key is unique and frictionless accepts it. The same pair is in live.
Decisions
| Decision | By | Basis |
|---|---|---|
| Accept the 2 alt-name cells | User, 2026-10-03 (session d33e1b7e): "in general I accept any changes that stem from updated source data" | Said in reply to the pl/ph question ("Accept both?"), which the user had left unanswered in the form. Recorded as the extended standing rule in docs/parity/p5.md |
Accept the 13 float_suffix_dropped cells | Known class signed off by the user in P4 (2026-10-02, docs/parity/p4.md) | Also listed in the same pl/ph question |
| Accept the case-only duplicate key | Orchestrator, after the user's general reply | It's in live and upstream alike; the reply didn't address it explicitly |
Rebuild the GeoNames-job layer (name cleaning + alternate names from the dump) instead of porting only the in-repo scripts, which would have emptied alternative_city_name | Agent: matches what live was built from | Not put to the user as a separate question; the handback listed it as the first folded step |
List PSA PSGC in the descriptor sources | Orchestrator, on landing (568cd10) | The agent flagged that only GeoNames was listed |
Add rapidfuzz==3.10.0 to requirements-producers.txt | Orchestrator, on landing (568cd10) | The agent couldn't edit outside datasets/ph/; the producer imports it lazily and the tests skip without it |
| Drop row, distinct-code and fill counts from README; keep admin-unit counts (17 regions, 87 provinces and districts, 82 provinces) | Agent, per the README counts rule | ATTRIBUTION.txt untouched |
Transforms carried over
Folded, in order, from the GeoNames job → build_base.py → enrich_admin.py (fetch_source.py, integrity_checker.py, package.py, publish_r2.py and the scripts README deleted):
- GeoNames job:
clean_nameon place_name and admin_name1–3 (parenthesised part dropped, punctuation → space, whitespace collapsed, e.g. "Manila CPO-PO Box# 1000 to 1099" → "Manila CPO PO Box 1000 to 1099");alternative_city_name= first non-numeric alternate name of the dump entry whose asciiname equals the cleaned place_name (last entry wins). build_base.py: null-ish literals ("nan", "none", "null", …) cleared and cells stripped; accuracy as an integer;admin_code1= ISO 3166-2:PH for all 17 regions (Metro ManilaNCR→00); an alternate equal to place_name (case-insensitive) dropped.enrich_admin.py:admin_code2= 9-digit PSGC code of the province or NCR district;admin_name3/admin_code3= the LGU by the rule cascade (NCR district, LGU name in province, NCR barangay, unique LGU name, barangay in province, unique barangay, NCR CPO anchor, rapidfuzz WRatio ≥ 92 within the province, code-sibling); otherwise a city GeoNames supplied is kept, with its PSGC code when the name matches.- No row added, dropped or reordered.
integrity_checker.py's hard gates are nowProducerErrors: 4-digit postal code, unique (postal_code, place_name), no null-ish cell, every region mapped and present, region name ↔ code one-to-one, coordinates inside the Philippines, accuracy 1–6, everyadmin_code3in the PSGC register. No row-count assert.
Open questions
.licensing-notes.mdstill carries counts (2,317 rows, 403 rows, …) and describes the old scripts; left for the end-of-epic sweep (pc-hfz).
Provenance
Reconstructed 2026-10-05 from the agent transcript d33e1b7e-5027-498a-a97f-ba914ee2524e/subagents/agent-ae607b241a17fc834.jsonl, the orchestrator session d33e1b7e-… (hold, question, user reply, landing and follow-up commit), the commit messages, the bd notes and close reason, and docs/parity/p4.md / p5.md.