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.
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
Explore with AIpostal-codes-bj
| Field | Type | Description | Title |
|---|---|---|---|
| country_code | string | ISO 3166-1 alpha-2 -- always BJ | Country Code |
| postal_code | string | Always empty -- Benin has no operational postal code system. Not a data gap; see ATTRIBUTION.txt. | Postal Code |
| place_name | string | Locality/place name (GeoNames populated place) | Place Name |
| admin_name1 | string | Department (ISO 3166-2:BJ spelling) -- all 12 covered; blank where GeoNames assigns a place to no department | Administrative Name 1 |
| admin_code1 | string | ISO 3166-2:BJ code | Administrative Code 1 |
| admin_name2 | string | Not populated in this release | Administrative Name 2 |
| admin_code2 | string | Not populated | Administrative Code 2 |
| admin_name3 | string | Not populated | Administrative Name 3 |
| admin_code3 | string | Not populated | Administrative Code 3 |
| latitude | number | GeoNames latitude (WGS84) | Latitude |
| longitude | number | GeoNames longitude (WGS84) | Longitude |
| accuracy | string | Not populated -- the GeoNames gazetteer dump carries no accuracy field | Accuracy |
| alternative_city_name | string | Not populated in this release | Alternative City Name |
Download
Download CSVAbout
- Last updated
- 6 October 2026
- Total rows
- 3,760
- Format
- CSV
- File size
- 183 kB
About this dataset
Benin (BJ): migration notes
Internal record of the P6 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.8.3
- Commit: see
git log -- datasets/bj/(P6 bj commit on feat/single-source-of-truth, basec51b72a) - Parity verdict:
format-only(gate: pass, exit 0); CRLF→LF only - Producer:
custom, refresh disabled
Sources
| Input | URL | Notes |
|---|---|---|
| GeoNames gazetteer dump | https://download.geonames.org/export/dump/BJ.zip | BJ.txt, filtered to feature class P. The old builder read a local sources/BJ.txt snapshot of this file |
| GeoNames admin1 table | https://download.geonames.org/export/dump/admin1CodesASCII.txt | Used only to check GeoNames' department labels against the crosswalk. The old builder read a local sources/geonames_admin1CodesASCII.txt snapshot |
- Both URLs are stable, unversioned GeoNames URLs. The fetch date and sha256 are recorded in
bj.inputs.json;--no-fetchreuses the cache. - Benin has no postal-code system and GeoNames has no postal export for BJ (
export/zip/BJ.zipis a 404), sopostal_codeis empty on every row.pipeline.postal_code_required: falsetells build.py this is intended.
Parity against the live public CSV (2026-10-05)
Rows: 3,760 live and 3,760 fresh, none only on one side, 0 changed cells, no cell classes. Once CRLF is normalised to LF the fresh bj.csv is byte-identical to the live CSV, including row order. Live sha256 6ffc99b4…, fresh 1a08c492… (the only difference is line endings).
No discrepancies to explain. The GeoNames dump at migration time still has 3,760 populated places, 14 of them on the reserved admin1 code 00, as on 2026-09-17.
Decisions
| Decision | By | Basis |
|---|---|---|
| Accept the CRLF→LF difference | Standing rule (P5 sign-off: row_order/CRLF-only pre-approved) | Equal rows, 0 changed cells |
| Drop the exact-count asserts (3,760 places, 14 unresolved) | P6 brief | Replaced by structural checks: all 12 departments present, primary key unique, GeoNames labels match the crosswalk |
An admin1 code other than 00/blank that isn't in the crosswalk stops the build | Agent: port choice | The old builder blanked it silently (only its exact unresolved-count assert would have caught it); blanking a real but new department would hide a crosswalk gap |
latitude/longitude typed number; accuracy stays string | Agent, per the brief | accuracy is empty on every row (the gazetteer dump has no accuracy field), so it isn't numeric data and doesn't get the GeoNames accuracy description |
primaryKey: [place_name, latitude, longitude] | Agent, from the produced CSV | Unique in the produced CSV; it is the old builder's own PK. (place_name, admin_code1) is not unique |
pipeline.postal_code_required: false | Agent | build.py refuses empty postal codes otherwise and names this flag; bj is the first dataset to use it |
Add admin1CodesASCII.txt to the descriptor sources | Agent | It is a fetched input |
| Field descriptions taken from the old builder's datapackage.json (minus counts) | Agent | The P3 generic descriptions said "Postal code for the location", which is wrong for bj |
Transforms carried over
From build_postal_codes_product.py:
- Feature class
Ponly;place_nameis the dump'snamecolumn; latitude/longitude copied verbatim. admin_code1→ ISO 3166-2:BJ via the bucket-code crosswalk (BJ.07–BJ.18),admin_name1in ISO spelling (Atakora→Atacora BJ-AK, Kouffo→Couffo BJ-KO). Every GeoNames label is checked so an upstream rename stops the build.- Reserved admin1
00→ blank admin_name1/admin_code1. postal_code,accuracy,alternative_city_nameand admin tiers 2–3 empty.- Sorted by (admin_code1, place_name), ties in dump order.
- Not ported: the old builder's own datapackage.json, README, ATTRIBUTION and zip writing (build.py / committed docs handle those) and
publish_r2.py.
Open questions
- Resolved:
README.mdwas the generic stub ("We don't have postal code data for Benin yet … No data is currently available"), which contradicts the published locality directory. It has no counts or licence line, so the agent left it; the orchestrator rewrote it afterwards (below). .licensing-notes.mdanddata/ATTRIBUTION.txtstill carry dated counts; left for pc-hfz.
Orchestrator follow-up (2026-10-05)
- README.md was the stale "no data yet" stub although the live CSV is a full locality directory. The orchestrator rewrote it from the old builder's README text, without counts and without the stale
licence_statusline. README text confirmed by the user (2026-10-05).