Postal Codes Dataset for Portugal, PT

473
Updated:
Files:1
Size:21.7 MB
Rows:206,942
Formats:csv

Postal Codes Dataset for Portugal, PT 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 — GeoNames (postal codes, place names, administrative names, coordinates, alternative names) license
20% off
$9.90$7.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-pt/
https://datahub.io/logistics/postal-codes-pt/_r/-/.licensing-notes.md
https://datahub.io/logistics/postal-codes-pt/_r/-/.migration-notes.md
https://datahub.io/logistics/postal-codes-pt/_r/-/ATTRIBUTION.txt
https://datahub.io/logistics/postal-codes-pt/_r/-/README.md
https://datahub.io/logistics/postal-codes-pt/_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-pt/_r/-/datapackage.yaml
README.md— documentation
https://datahub.io/logistics/postal-codes-pt/_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-pt-sample


About this dataset

Portugal (PT): 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.47 (closed 2026-10-05)
  • Commit: dbdaa34 (worktree commit 6f28f9e), landed in batch 6
  • Parity verdict: unexplained (the gate blocks on any unclassified cell); accepted as upstream drift
  • Producer: custom, refresh disabled

Sources

InputURLNotes
GeoNames postal exporthttps://download.geonames.org/export/zip/PT.zip
GeoNames gazetteer dumphttps://download.geonames.org/export/dump/PT.zipUsed for alternative_city_name; replaces the legacy R2 copy
CAOP freguesia table (core.json)https://aldeiasportuguesas.pt/dados/ → /data/aldeias-portuguesas-vYYYY.N/Republication of DGT CAOP 2025 + INE Censos 2021 (CC BY-SA 4.0). This is the old caop_freguesias.json
CAOP freguesia polygons (geo.geojson)same versioned directorySame DICOFRE keys
  • No CAOP URL was recorded anywhere in the old scripts. The agent found both files on the Aldeias Portuguesas download page.
  • The directory is versioned. The producer reads /dados/, takes the highest version that links both files (v2026.2 at migration time, the CAOP 2025 data live was built from), and records the resolved URLs in pt.inputs.json. --no-fetch reuses them.

Parity against the live zip (2026-10-03)

Rows: 206,942 live and 206,942 fresh, none only on one side. 18 changed cells, all in alternative_city_name. Every admin code and name matches live, including admin_code3 / admin_name3. Row order differs only within a postal code (GeoNames' tie order), which is covered by the row_order rule.

Cause: edits to the GeoNames dump (upstream drift).

RowsChangeCause
17 × "Ponte Nova" (e.g. 3105-449, 3720-479, 2350-466, 3250-037)Ponte da Cavada Velha → emptyNew dump entry geonameid 13712883 (BDG, no alternate names, modified 2026-09-25) has the same asciiname and comes after 7116987; the rule is "last matching entry wins"
3440-306 Francaempty → FrancaDump entry 8011428 now reads "Franca,França" (modified 2026-04-14), newer than the legacy R2 snapshot the old script copied from

Decisions

DecisionByBasis
Accept the 18 alt-name cellsStanding rule (upstream drift traced to source, user, 2026-10-03)Same kind as pl's 32 cells; recorded in the sign-off section of docs/parity/p5.md
Rebuild alternative_city_name from the GeoNames dump rather than copying the legacy R2 pt/pt.csvD1 (pl precedent)The old recover_alt_names.py read the live R2 object, which isn't a real source
Don't add an "alt name repeats place name" filterAgent: a faithful portpt's old script didn't have one, so the Franca echo stays
Keep the Aldeias Portuguesas republication; don't switch to DGT's own CAOP downloadsAgent: a faithful port; surfaced to the userThe old builder used it, and switching would be a source switch
admin_code2 that disagrees with CAOP now stops the buildAgentThe old script only reported it
Accept alphanumeric DICOFRE codes (\d{4}[0-9A-Z]{2})Agent: bug found during the portBarcelos and Guimarães pass 99 parishes and continue with letters (0302FA, 0308FE); live has 751 such rows. The admin_code3 description, which said "6 digits", was corrected

Transforms carried over

Folded from fetch_source.py → build_base.py → enrich_caop.py → spatial_join_freguesia.py → recover_alt_names.py → integrity_checker.py:

  • GeoNames codes and names copied verbatim as text (no pandas float coercion).
  • admin_code1 → ISO 3166-2:PT from the district/region name (GeoNames' number isn't ISO), with the canonical admin_name1. An unknown name is a ProducerError.
  • admin_code3 by CAOP name match: exact, then with the trailing bracketed part dropped, then an unambiguous pre-2013 union constituent. Azores and Madeira are keyed on source_region. With no match, GeoNames' unofficial code is cleared. (GeoNames' freguesia code is its own alphabetical numbering, not DICOFRE; e.g. Agadão is GeoNames 010101 but DICOFRE 010128.)
  • Then point-in-polygon (shapely STRtree, buffer(0) repair) for rows still uncoded, only inside the row's own concelho and only when exactly one polygon contains the point. admin_name3 is set to the official CAOP name.
  • The integrity checks are now ProducerErrors. The primary key is (postal_code, place_name). Rows keep GeoNames file order.

Open questions

  • Resolved (user, 2026-10-05, pc-28e.7.59): CAOP via Aldeias Portuguesas is accepted long term.
  • .licensing-notes.md still says "14,538 rows", which is a stale historical count. It was left alone; it belongs to the pc-hfz sweep.

Provenance

Reconstructed 2026-10-05 from the agent transcript 7df0c5be-a523-4080-87f9-6045a6a41515/subagents/agent-a0e0a20077716a524.jsonl, the orchestrator session 7df0c5be-…, the commit message and the bd close reason.