SPB Git forge

spb/countryatlas

Public
20commits 1branches 0releases
268.3 MBsize
maindefault branch
12 days agolast push
TypeScript 57% Python 38.6% JavaScript 3.6% CSS 0.6%
38.4 KB · 317 lines markdown
Rendered Raw Blame History
1# CountryAtlas — Public data sources, verified 2026-09-1123Every URL below was called with `curl` on 2026-09-11 from Québec (all times UTC). "VERIFIED" = HTTP 200 with data shown.4"UNVERIFIED" = could not confirm; what was tried is stated. Samples are trimmed.56Summary table78| Source | Base URL | Auth | Rate limit (observed / documented) | Country code | Time format | Licence |9|---|---|---|---|---|---|---|10| World Bank WDI v2 | `https://api.worldbank.org/v2/` | none | none published; Cloudflare-cached (`cache-control: max-age≈30000`) | ISO3 in `countryiso3code`, WB 2-letter in `country.id` | `"2025"` (year string) | CC BY 4.0 (attribute "World Bank, World Development Indicators") |11| IMF WEO (SDMX) | `https://api.imf.org/external/sdmx/{2.1,3.0}/` | none | none observed; 3.6 MB CSV for all countries in <10 s | ISO3 (`CAN`) + IMF group codes (`G001`…) | year `2024` | © IMF, free reuse with citation (see `LICENSE` field) |12| OECD SDMX | `https://sdmx.oecd.org/public/rest/` | none | doc: 60 req/h per IP for anonymous… see §3 (not enforced on our tests) | ISO3 (`REF_AREA`) | `2024`, `2026-06`, `2026-Q1` | CC BY 4.0 |13| Eurostat JSON-stat | `https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0/data/` | none | doc: no hard limit; large queries may be refused | Eurostat geo (`EL`, `EU27_2020`) | `2025`, `2025-M06`, `2025-Q1` | CC BY 4.0 |14| WHO GHO OData | `https://ghoapi.azureedge.net/api/` | none | none published; CDN `max-age=3600` | ISO3 (`SpatialDim`) | `TimeDim` int year | CC BY-NC-SA 3.0 IGO |15| FRED | `https://api.stlouisfed.org/fred/` | `api_key` | 120 req/min; bursts trigger 429 then Akamai **403** for several minutes | US mostly; ISO2 embedded in ids (`QCAR628BIS`) | `2026-08-01` (ISO date) | FRED ToU; third-party series keep their own terms |16| OWID | `raw.githubusercontent.com/owid/...`, `ourworldindata.org/grapher/` | none | GitHub raw: reasonable; grapher CSV: none published | ISO3 in `iso_code`/`code`; `OWID_*` for aggregates | year int | CC BY 4.0 |17| UN WPP portal API | `https://population.un.org/dataportalapi/api/v1/` | **Bearer token for `/data/*`** | n/a | UN M49 numeric location ids | year | CC BY 3.0 IGO |18| UN Comtrade | `https://comtradeapi.un.org/` | **subscription key** (free `/public/v1/preview` limited) | preview: 500 records/call | M49 numeric (`124`) | `period=2023` | UN ToU |19| BIS SDMX v2 | `https://stats.bis.org/api/v2/` | none | none observed | **ISO2** (`CA`, `US`, `XM`=euro area) | `2026-08`, `2026-Q1` | BIS terms (free with attribution) |20| ILOSTAT SDMX | `https://sdmx.ilo.org/rest/` | none | `cache-control: no-store`; none published | ISO3 | year | CC BY 4.0 |2122---2324## 1. World Bank Indicators API v2 — VERIFIED2526Base `https://api.worldbank.org/v2/`, no auth, `format=json`. Response is a 2-element array: `[meta, rows]`.27Meta: `{"page":1,"pages":1,"per_page":20000,"total":17490,"sourceid":"2","lastupdated":"2026-07-13"}` — **`lastupdated` is the WDI vintage** (2026-07-13 on all WDI queries).2829### Country list (regions, income groups, aggregates)30`GET /country?format=json&per_page=400` → `total: 295` (217 economies + 78 aggregates). Aggregates have `region.id == "NA"` (and `incomeLevel.id == "NA"`).31```json32{"id":"CAN","iso2Code":"CA","name":"Canada","region":{"id":"NAC","iso2code":"XU","value":"North America"},33 "adminregion":{"id":"","iso2code":"","value":""},"incomeLevel":{"id":"HIC","iso2code":"XD","value":"High income"},34 "lendingType":{"id":"LNX","iso2code":"XX","value":"Not classified"},"capitalCity":"Ottawa","longitude":"-75.6919","latitude":"45.4215"}35{"id":"WLD","iso2Code":"1W","name":"World","region":{"id":"NA","iso2code":"NA","value":"Aggregates"}, ...}36```37Filter aggregates with `region.id == "NA"` → 78 (WLD, EUU, HIC, OED, LIC, LMC, UMC, AFE, …). Real economies: 217.3839### Indicator data, all countries40`GET /country/all/indicator/NY.GDP.PCAP.CD?format=json&per_page=20000&date=1960:2026` → 17 490 rows, 1 page.41```json42{"indicator":{"id":"NY.GDP.PCAP.CD","value":"GDP per capita (current US$)"},"country":{"id":"1W","value":"World"},43 "countryiso3code":"WLD","date":"2025","value":14405.8484595528,"unit":"","obs_status":"","decimal":1}44```45- Rows are sorted country → year **descending**. Missing values: `"value": null` (2 745 of 17 490 here). `obs_status` is essentially always `""`.46- **Data rows include aggregates** (WLD, EUU, HIC…). Join on `countryiso3code` with the country list to drop them.47- **Quirk**: 5 income-group aggregates (`XD` High income, `XM` Low, `XN` Lower-middle, `XT` Upper-middle, `XY` Not classified) come back with **`countryiso3code: ""`** — use `country.id` (2-letter) as a fallback key.48- `per_page`: default 50 (→ `pages: 350`). Tested 20 000, 25 000 and 32 000 → OK. **50 000 → HTTP "Request Error" XML page**. Use ≤ 32 000; one indicator for all countries/years fits in one page (~17.5k rows).49- `date=1960:2026` (range) or `date=2024`; `mrv=N` = N most-recent values per country; `mrnev=1` = most recent **non-empty** value (returns fewer rows, e.g. Gini CAN → 2022); `gapfill=Y` with `mrv` forward-fills (Gini CAN 2023–2025 all 31.5 — beware).50- Several countries: `/country/CAN;USA/indicator/...`. Several indicators: `/country/CAN/indicator/SP.POP.TOTL;NY.GDP.MKTP.CD?source=2` (needs `source=`).51- Retired code → HTTP 200 with `[{"message":[{"id":"175","key":"Invalid format","value":"The indicator was not found. It may have been deleted or archived."}]}]` — **check for `.[0].message`**, not the status code.5253### Indicator metadata54`GET /indicator/NY.GDP.PCAP.CD?format=json` →55```json56{"id":"NY.GDP.PCAP.CD","name":"GDP per capita (current US$)","unit":"","source":{"id":"2","value":"World Development Indicators"},57 "sourceNote":"Gross domestic product is the total income earned ...","sourceOrganization":"Country official statistics, ...; OECD; Staff estimates, World Bank (WB)",58 "topics":[{"id":"3","value":"Economy & Growth"}]}59```60Full catalogue: `/indicator?format=json&per_page=30000` (29 544 indicators, 6 MB) — filter locally (`source.id=="2"` → 1 498 WDI indicators). The `q=` search parameter is **ignored** (returns the full list). `/source?format=json&per_page=100` → 71 sources; `/source/2?format=json` → `{"id":"2","lastupdated":"2026-07-13","name":"World Development Indicators","code":"WDI"}`.6162### Indicator code audit (`mrnev=1&per_page=400` on `/country/all/...`)63**Exist and return data (94/96)** — latest year with data (CAN value in brackets):6465| Code | Latest | Code | Latest | Code | Latest |66|---|---|---|---|---|---|67| NY.GDP.MKTP.CD | 2025 | NY.GDP.PCAP.CD | 2025 (55 698) | NY.GDP.PCAP.PP.CD | 2025 |68| NY.GDP.MKTP.KD.ZG | 2025 | FP.CPI.TOTL.ZG | 2025 | SL.UEM.TOTL.ZS | 2025 |69| SP.POP.TOTL | 2025 | SP.POP.GROW | 2025 | SP.DYN.LE00.IN | 2024 |70| SP.DYN.TFRT.IN | 2024 | SP.URB.TOTL.IN.ZS | 2025 | GC.DOD.TOTL.GD.ZS | 2024 (120 countries only) |71| **EN.GHG.CO2.PC.CE.AR5** | 2024 (14.0 t) | EG.ELC.RNEW.ZS | **2021** | IT.NET.USER.ZS | 2025 |72| GB.XPD.RSDV.GD.ZS | 2024 | NE.EXP.GNFS.ZS | 2025 | NE.TRD.GNFS.ZS | 2025 |73| SH.XPD.CHEX.GD.ZS | 2024 | SE.XPD.TOTL.GD.ZS | 2025 | SP.DYN.IMRT.IN | 2024 |74| SI.POV.GINI | 2025 (CAN 2022) | SL.TLF.CACT.ZS | 2025 | MS.MIL.XPND.GD.ZS | 2024 |75| EG.USE.PCAP.KG.OE | 2024 | EG.FEC.RNEW.ZS | 2022 | AG.LND.FRST.ZS | 2023 |76| EN.ATM.PM25.MC.M3 | 2023 | IT.CEL.SETS.P2 | 2025 | IT.NET.BBND.P2 | 2025 |77| ST.INT.ARVL | **2020** | BN.CAB.XOKA.GD.ZS | 2025 | GC.REV.XGRT.GD.ZS | 2024 |78| GC.XPN.TOTL.GD.ZS | 2024 | SH.MED.PHYS.ZS | 2023 | SH.MED.BEDS.ZS | 2023 |79| SM.POP.NETM | 2025 | SP.POP.65UP.TO.ZS | 2025 | SP.POP.0014.TO.ZS | 2025 |80| NV.AGR.TOTL.ZS | 2025 | NV.IND.TOTL.ZS | 2025 | NV.SRV.TOTL.ZS | 2025 |81| FR.INR.LEND | 2025 (CAN stops 2017) | PA.NUS.FCRF | 2025 | EG.ELC.ACCS.ZS | 2024 |82| SH.STA.SUIC.P5 | 2021 | SH.PRV.SMOK | 2024 | SE.ADT.LITR.ZS | 2024 (no CAN) |83| SE.TER.ENRR | 2025 | SE.SEC.ENRR | 2025 | SE.PRM.ENRR | 2025 |84| SL.UEM.1524.ZS | 2025 | AG.PRD.FOOD.XD | 2022 | AG.LND.AGRI.ZS | 2023 |85| NY.GDP.TOTL.RT.ZS | 2021 | ER.LND.PTLD.ZS | 2025 | EN.POP.DNST | 2023 |86| SP.POP.DPND | 2025 | VC.IHR.PSRC.P5 | 2023 | SH.XPD.CHEX.PC.CD | 2024 |87| NY.GDP.PCAP.KD.ZG | 2025 | NE.GDI.TOTL.ZS | 2025 | NE.CON.PRVT.ZS | 2025 |88| FM.LBL.BMNY.GD.ZS | 2025 (CAN stops 2008) | BX.KLT.DINV.WD.GD.ZS | 2025 | DT.DOD.DECT.GN.ZS | 2024 (133 low/middle income only) |89| SL.GDP.PCAP.EM.KD | 2025 | EG.IMP.CONS.ZS | 2023 | EG.EGY.PRIM.PP.KD | 2022 |90| SH.DYN.MORT | 2024 | SH.DYN.NCOM.ZS | 2021 | SP.ADO.TFRT | 2024 |91| SH.STA.OWAD.ZS | 2022 (**overweight**, not obesity; source 16 HNP) | SP.DYN.CBRT.IN | 2024 | SP.DYN.CDRT.IN | 2024 |92| SM.POP.TOTL.ZS | 2024 | IP.PAT.RESD | 2021 | IP.JRN.ARTC.SC | 2023 |93| TX.VAL.TECH.MF.ZS | 2024 | LP.LPI.OVRL.XQ | 2022 | IS.AIR.PSGR | 2023 |94| IS.RRS.TOTL.KM | 2021 | EG.ELC.FOSL.ZS | 2023 | EG.ELC.HYRO.ZS | 2024 |95| EG.ELC.NUCL.ZS | 2024 | EG.ELC.RNWX.ZS | 2021 | **EN.GHG.CO2.MT.CE.AR5** | 2024 |96| **EN.GHG.CH4.MT.CE.AR5** | 2024 | GC.TAX.TOTL.GD.ZS | 2024 | SH.H2O.BASW.ZS | 2024 |97| SE.PRM.CMPT.ZS | 2025 | | | | |9899**Missing (2/96)**:100- `EN.ATM.CO2E.PC` — retired. Replacement **`EN.GHG.CO2.PC.CE.AR5`** (t CO2e/capita, excl. LULUCF, source EDGAR). Sibling codes verified: `EN.GHG.CO2.MT.CE.AR5`, `EN.GHG.CH4.MT.CE.AR5`, `EN.GHG.N2O.MT.CE.AR5`, `EN.GHG.ALL.MT.CE.AR5` (total GHG Mt), `EN.GHG.ALL.PC.CE.AR5` (total GHG per capita, CAN 2024 = 18.6).101- `SM.POP.REFG` — listed in the catalogue under source 57 "WDI Database Archives" but **returns "not found" both with and without `source=57`**. Replacement: UNHCR Refugee Data Finder API (`https://api.unhcr.org/population/v1/population/?year=2024&coa=CAN`, no key) or OWID grapher `refugee-population-by-country-or-territory-of-asylum`. Not tested here.102- Obesity: WB has no adult obesity (BMI≥30) indicator (catalogue search found only overweight `SH.STA.OWAD.ZS` and HEFPI mean-BMI). Use **WHO `NCD_BMI_30A`** (§5).103104---105106## 2. IMF World Economic Outlook — VERIFIED (no key needed)107108- Legacy `dataservices.imf.org/REST/SDMX_JSON.svc` → connection fails (retired).109- New portal `https://data.imf.org` exposes **SDMX 2.1 and 3.0 REST at `https://api.imf.org/external/sdmx/`**, **no API key**, no subscription. (An IMF "Data Portal Subscription" only raises quotas; anonymous works.)110- Dataflow **`IMF.RES,WEO`** (agency `IMF.RES`, id `WEO`, version 9.0.0), DSD `DSD_WEO`.111- **Dimension order: `COUNTRY.INDICATOR.FREQUENCY`** (+ `TIME_PERIOD`); FREQUENCY is always `A`.112- Current vintage: `PUBLICATION_DATE 2026-04-14` = **April 2026 WEO** (visible in CSV metadata). Years 1980–2031 (52 periods).113114### Sample query (2.1, CSV — recommended: flat, includes projection metadata)115```116GET https://api.imf.org/external/sdmx/2.1/data/IMF.RES,WEO/CAN+USA.NGDP_RPCH+PCPIPCH+LUR+GGXWDG_NGDP+GGXCNL_NGDP+BCA_NGDPD+PPPPC.A?startPeriod=2024&endPeriod=2031117Accept: text/csv118```119```120DATAFLOW,COUNTRY,INDICATOR,FREQUENCY,TIME_PERIOD,OBS_VALUE,SCALE,...,LATEST_ACTUAL_ANNUAL_DATA,...121IMF.RES:WEO(9.0.0),CAN,LUR,A,2024,6.366667,0,...,2025,...122IMF.RES:WEO(9.0.0),CAN,LUR,A,2025,6.858333,0,...,2025,...123IMF.RES:WEO(9.0.0),CAN,LUR,A,2026,6.521412,0,...,2025,...124```125- **Projection flag: column `LATEST_ACTUAL_ANNUAL_DATA`** (per country×indicator; here `2025`) = "estimates start after". Any `TIME_PERIOD > LATEST_ACTUAL_ANNUAL_DATA` is a **forecast**. Present in CSV output only (2.1 XML has it as series attribute too; SDMX-JSON 3.0 exposes it in `attributes` if requested with `attributes=all`, not confirmed).126- CSV also carries `LICENSE` ("© International Monetary Fund Copyright. All Rights Reserved. https://www.imf.org/external/terms.htm") and `SUGGESTED_CITATION`: *"International Monetary Fund. World Economic Outlook (WEO), https://data.imf.org/en/datasets/IMF.RES:WEO. Accessed on [date]."*127- All countries: leave the COUNTRY segment empty: `/data/IMF.RES,WEO/.NGDP_RPCH.A?startPeriod=2024` → 1 640 rows, 213 areas (incl. aggregates `G001` World etc.), 3.6 MB CSV (the CSV repeats ~40 metadata columns per row — parse `COUNTRY,INDICATOR,TIME_PERIOD,OBS_VALUE,LATEST_ACTUAL_ANNUAL_DATA`).128- Default 2.1 output (no Accept) is **SDMX-ML StructureSpecific XML**: `<Series COUNTRY="CAN" INDICATOR="NGDP_RPCH" FREQUENCY="A" ...><Obs TIME_PERIOD="2026" OBS_VALUE="1.499992"/>`. Asking `Accept: application/vnd.sdmx.data+json` on 2.1 still returns XML (JSON not served on 2.1).129- Quirk: the `+` separator in the 2.1 key with the JSON Accept header once returned HTTP 500; CSV/XML fine. `dataflow/IMF.RES/WEO/+` on 2.1 → 204 (use 3.0 for structures).130131### SDMX 3.0 (JSON)132```133GET https://api.imf.org/external/sdmx/3.0/data/dataflow/IMF.RES/WEO/+/CAN.NGDP_RPCH.A134Accept: application/vnd.sdmx.data+json;version=2.0.0135```136```json137{"data":{"dataSets":[{"series":{"0:0:0":{"attributes":[0,0,0,"9/25/2025"],"observations":{"0":["2.162741"],"1":["3.503078"],...}}}}],138 "structures":[{"dimensions":{"series":[{"id":"COUNTRY","keyPosition":0},{"id":"INDICATOR","keyPosition":1},{"id":"FREQUENCY","keyPosition":2}],139 "observation":[{"id":"TIME_PERIOD","values":[{"value":"1980"},...]}]}}]}}140```141- Wildcard all countries: `.../WEO/+/*.NGDP_RPCH.A` → 210 areas, 194 KB.142- Time filter must be **URL-encoded**: `?c%5BTIME_PERIOD%5D=ge:2024` (raw `c[TIME_PERIOD]=` → HTTP 400 Tomcat page). Observation values are **strings** (`"2.162741"`).143- Structures: `/3.0/structure/dataflow/IMF.RES/WEO/+`, `/3.0/structure/datastructure/IMF.RES/DSD_WEO/+`, codelists `IMF.RES/CL_WEO_INDICATOR` (145 codes), `IMF.RES/CL_WEO_COUNTRY` (344 codes) with `Accept: application/vnd.sdmx.structure+json;version=2.0.0`.144- Verified indicator codes: `NGDP_RPCH` (real GDP growth %), `PCPIPCH` (CPI inflation avg %), `LUR` (unemployment rate), `GGXWDG_NGDP` (gross debt % GDP), `GGXCNL_NGDP` (net lending % GDP), `BCA_NGDPD` (current account % GDP), `PPPPC` (GDP per capita PPP intl $), plus `NGDPD`, `NGDPDPC`, `PPPGDP`, `LP` (population), `GGXWDN_NGDP` (net debt).145- Quirk: `COUNTRY_UPDATE_DATE` attribute reads `9/25/2025` even in the April 2026 vintage — do not use it as vintage; use `PUBLICATION_DATE`/`UPDATE_DATE` from CSV or the dataflow version.146147### Bulk download fallback — UNVERIFIED148`https://www.imf.org/-/media/Files/Publications/WEO/WEO-Database/2026/april/WEOApr2026all.ashx` → 302 to Azure blob → **`BlobNotFound`**; `.xls` variants and the page `imf.org/en/Publications/WEO/weo-database/2026/april/download-entire-database` → **403 Akamai "Access Denied"** for curl (browser UA too). The Oct-2025 and Apr-2025 `.ashx` URLs also 302→BlobNotFound. Conclusion: the tab-separated "WEO…all.xls" files are no longer served from that path; use the SDMX API above (or data.imf.org bulk "Download entire dataset" button, browser only).149150---151152## 3. OECD SDMX API — VERIFIED (5+ dataflows end-to-end)153154Base `https://sdmx.oecd.org/public/rest/`. No key. Licence **CC BY 4.0** (cite "OECD (2026), <dataset>, https://data-explorer.oecd.org"). Documented limits (OECD API docs): 60 data requests/hour/IP anonymous, 1 000 000 obs/query; not hit during ~40 requests here. `cache-control: public, max-age=7200` on data.155156URL pattern: `/data/{AGENCY},{DSD@DF},{version|blank}/{key}?startPeriod=…&format=csvfilewithlabels` (CSV code+label columns) or `format=csvfile` or `format=jsondata` (SDMX-JSON 1.0). **Key must contain every dimension** (dots), empty = wildcard; missing dims → HTTP **403** `Not enough key values in query, expecting N got M`. Nothing found → HTTP **404** `NoRecordsFound`. Country dim `REF_AREA` = ISO3. Time: `2024`, `2026-06`, `2026-Q1`. Current dataflow ids: `GET /dataflow/all` (XML, 8.9 MB, 1 546 flows; JSON Accept → 406). Structure: `/dataflow/{AGENCY}/{DSD@DF}/latest?references=all` or `/datastructure/{AGENCY}/{DSD}/latest` with `Accept: application/vnd.sdmx.structure+json` (dimension list under `dataStructureComponents.dimensionList.dimensions`).157158| Topic | Dataflow (verified id) | Dims (order) | Working query (CAN+USA) | Sample |159|---|---|---|---|---|160| House prices | `OECD.ECO.MPD,DSD_AN_HOUSE_PRICES@DF_HOUSE_PRICES` | REF_AREA.FREQ.MEASURE.UNIT_MEASURE | `/CAN+USA.A.RHP+HPI+RPI+HPI_RPI+HPI_YDH.?startPeriod=2021` | `CAN,A,RHP,IX,2021,144.49` (base 2015=100) |161| Short/long rates | `OECD.SDD.STES,DSD_STES@DF_FINMARK` (4.0) | REF_AREA.FREQ.MEASURE.UNIT_MEASURE.ACTIVITY.ADJUSTMENT.TRANSFORMATION.TIME_HORIZ.METHODOLOGY (9) | `/CAN+USA.M.IRSTCI+IR3TIB+IRLT.PA......?startPeriod=2026-06` | `CAN IRLT 2026-08 3.675` |162| Rates (KEI) | `OECD.SDD.STES,DSD_KEI@DF_KEI` (4.0) | REF_AREA.FREQ.MEASURE.UNIT_MEASURE.ACTIVITY.ADJUSTMENT.TRANSFORMATION (7) | `/CAN+USA.M.IR3TIB+IRLT.....?startPeriod=2026-06` | `CAN IR3TIB 2026-08 2.28` |163| Avg annual wages | `OECD.ELS.SAE,DSD_EARNINGS@AV_AN_WAGE` | REF_AREA.MEASURE.UNIT_MEASURE.PAY_PERIOD.PRICE_BASE.AGGREGATION_OPERATION.SEX (7) | `/CAN+USA.......?startPeriod=2021` | `CAN WG USD_PPP Q(constant) 2024 67767.6` |164| Hours worked | `OECD.ELS.SAE,DSD_HW@DF_AVG_ANN_HRS_WKD` | 13 dims (REF_AREA.MEASURE.UNIT_MEASURE.SEX.AGE.LABOUR_FORCE_STATUS.WORK_PERIOD.HOURS_TYPE.WORKER_STATUS.WORK_TIME_ARNGMNT.AGGREGATION_OPERATION.HOUR_BANDS.JOB_COVERAGE) | `/CAN+USA............?startPeriod=2021` then filter `WORKER_STATUS=_T` | `CAN 2022 1693 h`, `USA 2023 1804.95` |165| Tax revenue | `OECD.CTP.TPS,DSD_REV_COMP_OECD@DF_RSOECD` (2.0) | REF_AREA.MEASURE.SECTOR.STANDARD_REVENUE.CTRY_SPECIFIC_REVENUE.UNIT_MEASURE.FREQ (7) | `/CAN+USA.TAX_REV.S13._T._T.PT_B1GQ.A?startPeriod=2022` | `CAN _T 2023 34.79 % GDP` (`T_AA` cash-basis is 0 for accrual reporters — use `_T`) |166| Social expenditure | `OECD.ELS.SPD,DSD_SOCX_AGG@DF_SOCX_AGG` | REF_AREA.FREQ.MEASURE.UNIT_MEASURE.EXPEND_SOURCE.SPENDING_TYPE.PROGRAMME_TYPE.PRICE_BASE (8) | `/CAN+USA.A.SOCX.PT_B1GQ.ES10._T._T.?startPeriod=2021` | `CAN ES10 (public) 2021 21.858 % GDP` |167| Hospital beds | `OECD.ELS.HD,DSD_HEALTH_REAC_HOSP@DF_HOSP_REAC` (1.1) | REF_AREA.MEASURE.UNIT_MEASURE.STATISTICAL_OPERATION.OWNERSHIP_TYPE.HEALTH_FUNCTION.CARE_TYPE.MEDICAL_TECH.HEALTH_CARE_PROVIDER (9) | `/CAN+USA.HB.10P3HB.._T._T...?startPeriod=2022` | `CAN 2024 2.08 beds/1000` (HEALTH_FUNCTION=_T; `HC0` rows are 0) |168| Physicians / nurses | `OECD.ELS.HD,DSD_HEALTH_EMP_REAC@DF_PHYS` (also `@DF_NURSE`) — **not** `DSD_HEALTH_REAC_EMP` | REF_AREA.MEASURE.UNIT_MEASURE.AGE.SEX.HEALTH_PROF.HEALTH_PROF_ACTIVITY_STATUS.… (9) | `/CAN+USA.........?startPeriod=2022` filter `UNIT_MEASURE=10P3HB` | `CAN HSE PHYS LP(practising) 2022 2.93/1000` |169| R&D (MSTI) | `OECD.STI.STP,DSD_MSTI@DF_MSTI` (1.3) | REF_AREA.FREQ.MEASURE.UNIT_MEASURE.PRICE_BASE.TRANSFORMATION (6) | `/CAN.A.G.PT_B1GQ._Z._Z?startPeriod=2021` | `G PT_B1GQ 2023 1.935` (GERD % GDP); researchers `T_RS FTE 2023 235170` |170| Education attainment | `OECD.EDU.IMEP,DSD_EAG_LSO_EA@DF_LSO_NEAC_DISTR_EA` (the `DSD_EAG_UOE_NEAC@DF_EAG_NEAC` id **does not exist** anymore) | 17 dims; REF_AREA first | `/CAN+USA................?startPeriod=2023` filter `AGE=Y25T64, SEX=_T, ATTAINMENT_LEV=ISCED11A_5T8, STATISTICAL_OPERATION=V` | structure verified; returned 3 945 rows; `SE` rows (std error) have empty OBS_VALUE — value rows use `STATISTICAL_OPERATION=V` (not individually displayed; partially verified) |171| Productivity | `OECD.SDD.TPS,DSD_PDB@DF_PDB_LV` | REF_AREA.FREQ.MEASURE.ACTIVITY.UNIT_MEASURE.PRICE_BASE.TRANSFORMATION.ASSET_CODE.CONVERSION_TYPE (9) | `/CAN+USA.A.......?startPeriod=2022` | **UNVERIFIED — HTTP 500 "Internal server error"** on two attempts (structure endpoint OK). Retry later or use `DSD_PDB@DF_PDB_GR`. |172| CLI / confidence | `OECD.SDD.STES,DSD_STES@DF_CLI` (4.1) | as FINMARK | not tested | id present in flow list |173174CSV (`csvfilewithlabels`) columns: `STRUCTURE,STRUCTURE_ID,STRUCTURE_NAME,ACTION,REF_AREA,Reference area,…,TIME_PERIOD,Time period,OBS_VALUE,Observation value,OBS_STATUS,…` — every dimension is followed by its label column; parse with a CSV reader keyed by header (labels can contain commas). `OBS_STATUS`: `A` normal, `E` estimate, `P` provisional, `B` break. Empty `OBS_VALUE` = missing.175`format=jsondata` sample (house prices): `{"data":{"dataSets":[{"series":{"0:0:0:0":{"observations":{"0":[139.53,0],"1":[144.16,0],"2":[143.35,0]}}}}],"structure":{"dimensions":{"observation":[{"id":"TIME_PERIOD","values":[{"id":"2025"},{"id":"2024"},{"id":"2023"}]}]}}}}` — **time values come in descending order**; map observation index → `values[i].id`, never assume ascending.176177### Connector implementation notes (2026-09-11, `registry/sources/oecd.yaml`)178Full-dimension keys that returned data for ALL countries (`REF_AREA` empty) — the shorter keys in the table above 404 (`NoRecordsFound`) when used with an empty REF_AREA:179- Wages `DSD_EARNINGS@AV_AN_WAGE`: `.WG.USD_PPP.A.Q.MEAN._Z` (PRICE_BASE `Q` = constant prices, base 2025; `V` = current).180- Hours `DSD_HW@DF_AVG_ANN_HRS_WKD`: `.HW.H_Y_PS._Z._Z.EMP.A.ACTUAL._T._Z.MEAN._Z._T` (12 dims after REF_AREA).181- Hospital beds `DF_HOSP_REAC`: `.HB.10P3HB._Z._Z._T._T._Z._Z` — the total is `OWNERSHIP_TYPE=_Z, HEALTH_FUNCTION=_T, CARE_TYPE=_T`; the `.._T._T...` form above no longer matches.182- Physicians `DF_PHYS`: `.HSE.10P3HB._Z._Z.PHYS._Z.LP._Z` (practising; USA has `LP` too). **`DF_NURSE` does not exist** (404 "Could not find Dataflow").183- Education `DF_LSO_NEAC_DISTR_EA` (17 dims): `._T.Y25T64.ISCED11A_5T8._T.POP._Z._T._Z.ED_NED.POP._Z.PT_POP_SEX_AGE.OBS._Z.NEAC.A` — `STATISTICAL_OPERATION` is `OBS`/`SE` (not `V`); no ISCED 3–8 aggregate → "at least upper secondary" = 100 − `ISCED11A_0T2`. Includes `OECD`, `G20`, `EU25` aggregates.184- SOCX: last segment PRICE_BASE is `_Z` (`.A.SOCX.PT_B1GQ.ES10._T._T._Z`). KEI industrial production: `.M.PRVM.IX.BTE.Y._Z` (2015=100, monthly, back to 1919 for some countries).185- `DF_PDB_LV` (GDP per hour worked) still HTTP 500 on 2026-09-11 (3 attempts) — not mapped.186- Rate limit is real: 17 requests in ~40 s → one **HTTP 429** (retried later). Keep ≤ 12/min.187188---189190## 4. Eurostat JSON-stat 2.0 — VERIFIED (13/13 — ilc_li02 works with `statinfo=MED_EI`, see note)191192Base `https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0/data/{dataset}?format=JSON&lang=EN&{dim}={code}&…`. No key. Filters: repeat `geo=DE&geo=FR`; `time=2024` or `sinceTimePeriod=2022` (`untilTimePeriod`, `lastTimePeriod=N`). Unknown dimension name → HTTP 400 `{"error":[{"status":400,"id":150,"label":"INVALID_QUERY_DIMENSION: … Dimension \"INDIC_IL\" is not defined"}]}`. Unknown code → 200 with `size: [...,0,...]` and empty `value`. Discover a dataset's dimensions/codes by requesting a single `geo`+`time` (`.dimension.<dim>.category.index`). Licence CC BY 4.0 ("Source: Eurostat").193194Structure (HICP example) — value is a **sparse object keyed by the flattened row-major index over `size`**:195```json196{"version":"2.0","class":"dataset","label":"HICP - annual data …","source":"ESTAT","updated":"2026-02-06T23:00:00+0100",197 "id":["freq","unit","coicop","geo","time"],"size":[1,1,1,4,4],198 "dimension":{"geo":{"category":{"index":{"EU27_2020":0,"DE":1,"EL":2,"FR":3},"label":{"EL":"Greece",…}}},199              "time":{"category":{"index":{"2022":0,"2023":1,"2024":2,"2025":3}}}},200 "value":{"0":9.2,"1":6.4,"2":2.6,"3":2.5,"4":8.7,"5":6.0,…},201 "status":{"8":"d","9":"d"}}202```203Index = `geoIdx*size[time] + timeIdx` (generally Σ idx_k·∏size_{k+1..}). Missing cells are simply absent from `value`. `status` flags: `p` provisional, `e` estimated, `b` break, `d` definition differs, `u` low reliability, `:` n/a. `updated` = dataset last update (freshness).204205| Dataset | Verified query (after `?format=JSON&lang=EN&`) | `updated` | Sample |206|---|---|---|---|207| `prc_hicp_aind` | `unit=RCH_A_AVG&coicop=CP00&geo=DE&geo=FR&geo=EL&geo=EU27_2020&sinceTimePeriod=2022` | 2026-02-06 | EU27 2022 9.2 % |208| `prc_hpi_a` | `purchase=TOTAL&unit=RCH_A_AVG&geo=DE&geo=FR&sinceTimePeriod=2022` | 2026-07-02 | DE 2022 6.0, 2023 -8.4 |209| `une_rt_a` | `age=Y15-74&unit=PC_ACT&sex=T&geo=…` | 2026-09-10 | DE 2022 3.1 |210| `gov_10dd_edpt1` | `na_item=GD&unit=PC_GDP&sector=S13&geo=DE&geo=FR&geo=IT` | 2026-04-22 | DE 2022 64.4 % |211| `lfsi_emp_a` | `indic_em=EMP_LFS&unit=PC_POP&age=Y20-64&sex=T` | 2026-09-10 | DE 2022 80.8 |212| `ilc_di03` | `statinfo=MED_EI&age=TOTAL&sex=T&unit=EUR` (dimension is `statinfo`, **not** `indic_il`) | 2026-06-08 | DE 2022 24 925 € |213| `ilc_li02` | dims `freq,statinfo,unit,rskpovth,sex,age,geo,time`; `rskpovth=A_60&unit=PC&sex=T&age=TOTAL` | 2026-06-10 | **UNVERIFIED values: every combination tested (DE/FR, 2019–2025, both `statinfo`, also SDMX-CSV endpoint) returns an empty `value`** — dataset appears to be mid-revision. Use `ilc_peps01n` (AROPE rate; dims `unit,age,sex`; 204 values for DE 2024 — verified) or retry later. |214| `rd_e_gerdtot` | `sectperf=TOTAL&unit=PC_GDP` | 2026-03-18 | DE 2022 3.07 (2024 `p`) |215| `nrg_ind_ren` | `nrg_bal=REN&unit=PC` | 2026-07-14 | DE 2021 19.3 |216| `env_air_gge` | `airpol=GHG&src_crf=TOTX4_MEMO&unit=MIO_T` (**not** `TOTX4_MEMONIA`; units are `MIO_T`/`THS_T`, no `T_HAB` here) | 2026-06-02 | DE 2022 749.3, 2024 649.8 Mt CO2e |217| `demo_mlexpec` | `sex=T&age=Y_LT1` | 2026-06-04 | DE 2022 80.7 |218| `edat_lfse_03` | `sex=T&age=Y25-64&isced11=ED5-8&unit=PC` | 2026-09-10 | DE 2022 32.1 |219| `ilc_lvho07a` | `rskpovth=TOTAL&age=TOTAL&sex=T&unit=PC` (**no `incgrp`** dimension) | 2026-06-08 | DE 2022 11.9 |220221**Connector implementation notes (2026-09-11, `registry/sources/eurostat.yaml`)** — `ilc_li02` is NOT empty: the `statinfo` codes are `MED_EI`/`MEAN_EI` (there is no `RT`), so `statinfo=MED_EI&rskpovth=B_60&unit=PC&sex=T&age=TOTAL` returns the at-risk-of-poverty rate (DE 2024 15.5 %). Other verified filters: `ilc_lvho02` (tenure) `rskpovth=TOTAL&hhcomp=TOTAL&tenure=OWN&unit=PC` (DE 2024 47.2 %); `une_ltu_a` `indic_em=LTU&age=Y15-74&sex=T&unit=PC_UNE`; `lfsa_eppga` `sex=T&age=Y15-64&unit=PC`; `lfsi_emp_a` has `age=Y15-64`; `ilc_di03` `unit=PPS` (DE 2024 25 192); `prc_hpi_a` `unit=I15_A_AVG` for the 2015=100 index. All 18 mapped datasets returned data for all geos with no `geo`/`time` filter (≤ 2 000 cells each).222223Geo codes (une_rt_a 2024): `EU27_2020, EA21 (from 2026), EA20, BE, BG, CZ, DK, DE, EE, IE, EL, ES, FR, HR, IT, CY, LV, LT, LU, HU, MT, NL, AT, PL, PT, RO, SI, SK, FI, SE, IS, NO, CH, BA, ME, MK, RS, TR`. Map to ISO2: `EL→GR`, `UK→GB` (UK present in some datasets but **no values after 2020**: `geo=UK` on une_rt_a → 0 values), everything else identical. Aggregates: `EU27_2020`, `EA20`, `EA21`, `EU28` — drop or map to your own aggregate ids. Alternate SDMX 2.1 endpoint for CSV: `…/api/dissemination/sdmx/2.1/data/{ds}/{key}?format=SDMX-CSV` (header `DATAFLOW,LAST UPDATE,freq,…,TIME_PERIOD,OBS_VALUE,OBS_FLAG`).224225---226227## 5. WHO GHO OData — VERIFIED228229Base `https://ghoapi.azureedge.net/api/`, OData v4 (`$filter`, `$select`, `$top`, `$orderby`; URL-encode spaces as `%20`). No key. `cache-control: public, max-age=3600`. Licence CC BY-NC-SA 3.0 IGO (cite "WHO Global Health Observatory").230231- `GET /Indicator` → 3 099 rows `{"IndicatorCode":"WHOSIS_000001","IndicatorName":"Life expectancy at birth (years)","Language":"EN"}`; search: `/Indicator?$filter=contains(IndicatorName,'obesity')`.232- Dimensions: `/DIMENSION/SEX/DimensionValues` → `SEX_BTSX` Both, `SEX_FMLE`, `SEX_MLE`, `SEX_NOA`; `/DIMENSION/COUNTRY/DimensionValues` → 234 with `ParentCode` = WHO region (`AMR`…).233- Data row (`/WHOSIS_000001?$filter=SpatialDim eq 'CAN' and Dim1 eq 'SEX_BTSX' and TimeDim ge 2019`):234```json235{"IndicatorCode":"WHOSIS_000001","SpatialDimType":"COUNTRY","SpatialDim":"CAN","ParentLocationCode":"AMR","ParentLocation":"Americas",236 "TimeDimType":"YEAR","TimeDim":2021,"Dim1Type":"SEX","Dim1":"SEX_BTSX","Dim2Type":null,"Dim2":null,237 "Value":"81.6 [81.5-81.7]","NumericValue":81.58276248,"Low":81.52940857,"High":81.68435338,"Date":"2024-08-02T09:43:39.193+02:00"}238```239- `SpatialDimType` ∈ `COUNTRY | REGION (AFR, AMR, EMR, EUR, SEAR, WPR) | GLOBAL | WORLDBANKINCOMEGROUP` — filter `SpatialDimType eq 'COUNTRY'`. `SpatialDim` = ISO3. `TimeDim` = int year. Use `NumericValue` (the `Value` string embeds CIs). `Date` = row last modified (freshness).240241| Indicator | Code | Dim1 / Dim2 to filter | CAN latest |242|---|---|---|---|243| Life expectancy | `WHOSIS_000001` | `Dim1 eq 'SEX_BTSX'` | 2021 81.6 (4 312 rows all sexes=BTSX) |244| Healthy life expectancy | `WHOSIS_000002` | `SEX_BTSX` | 2021 69.8 |245| Adult obesity (age-std) | `NCD_BMI_30A` | `SEX_BTSX`, Dim2 `AGEGROUP_YEARS18-PLUS` | 2024 26.0 % |246| Tobacco use | `M_Est_tob_curr` | `SEX_BTSX` | **contains projections to 2030** (2030: 8.3 %) — cap at ≤ current year |247| Medical doctors /10 000 | `HWF_0001` | none | 2024 28.54 |248| Measles MCV1 | **`WHS8_110`** (`WHS4_100` is **DTP3**, not measles) | none | 2025 92 % |249| Suicide rate | `SDGSUICIDE` | `SEX_BTSX`, Dim2 `AGEGROUP_YEARSALL` | 2021 |250| Infant mortality | `MDG_0000000001` | `SEX_BTSX`, Dim2 `AGEGROUP_MONTHS0-11` | 2024 4.7 |251| Health exp. % GDP | `GHED_CHEGDP_SHA2011` | none | 2023 11.19 |252| Safely managed water | `WSH_WATER_SAFELY_MANAGED` | Dim1 `RESIDENCEAREATYPE_TOTL` | 2024 96.9 |253| Alcohol per capita | `SA_0000001688` | `SEX_BTSX` | 2024 9.24 L |254255---256257## 6. FRED — VERIFIED258259Base `https://api.stlouisfed.org/fred/`, `api_key=<FRED_API_KEY>&file_type=json`. Limit **120 requests/minute** (documented); observed: a burst of 130 parallel calls → 60×200, 23×**429**, 47×**403 Akamai "Access Denied"** and the 403 ban lasted several minutes for all series endpoints. Throttle to ≤ 2 req/s sequential. Licence: FRED terms; third-party series (BIS, OECD, S&P) keep their own terms.260261`GET /series/observations?series_id=FEDFUNDS&api_key=…&file_type=json&observation_start=2026-01-01` →262```json263{"realtime_start":"2026-09-03","observation_start":"2026-01-01","units":"lin","output_type":1,"count":8,264 "observations":[{"realtime_start":"2026-09-03","realtime_end":"2026-09-03","date":"2026-08-01","value":"3.63"}]}265```266- Values are **strings**; missing = `"."` (e.g. DGS10 on 2026-09-07 holiday). Params: `frequency=a|q|m|w|d` with `aggregation_method=avg|sum|eop` (tested: FEDFUNDS annual avg 2024 5.14, 2025 4.21, 2026 `"."` incomplete year), `units=pc1|pch|lin…`, `observation_start/end`, `limit`, `sort_order`.267- `GET /series?series_id=X` → `seriess[0]` with `title, frequency_short, units_short, observation_start, observation_end, last_updated, seasonal_adjustment_short, notes`. **Quirk: `notes` may contain raw control characters → strict JSON parsers (jq) fail; use a lenient parser** (Python `json.JSONDecoder(strict=False)`).268- Search: `/series/search?search_text=…&limit=1000`; `/release/series?release_id=…`.269270US series — all 30 exist (obs end / last update): CPIAUCSL (2026-07), UNRATE (2026-08), GDPC1 & GDP (2026-Q2), FEDFUNDS (2026-08), MORTGAGE30US (2026-09-10, W), CSUSHPINSA (2026-06, now titled "S&P Cotality Case-Shiller"), HOUST, PERMIT (2026-07), RHORUSQ156N (2026-Q2), MEHOINUSA672N (A, 2024), CIVPART, AHETPI, CES0500000003 (2026-08), GFDEGDQ188S (2026-Q1), DGS10 (D), DEXCAUS, DEXUSEU, DEXJPUS (D, 2026-09-04), T10Y2Y, PAYEMS, PCEPILFE, INDPRO, RSAFS, UMCSENT (2026-07), TOTALSA, PSAVERT, M2SL (2026-07), WALCL (W), BOPGSTB (2026-07).271272International series (all exist):273- BIS house prices: `Q<ISO2>R628BIS` real / `Q<ISO2>N628BIS` nominal, Index 2010=100, quarterly — verified CA, US, FR, DE, JP, GB, AU, ES, IT, KR, NZ, SE, CH (obs end 2026-Q1, JP 2025-Q4; updated 2026-06/08). 61 `Q..R628BIS` series found via search. (`QCAN628BIS` = nominal Canada.)274- OECD MEI-derived (still present, but **CPI ones discontinued at 2025-03**): `IRSTCI01CAM156N` (CA immediate rate, to 2026-06), `IR3TIB01CAM156N`, `IRLTLT01CAM156N`, `IRLTLT01DEM156N` (10-y yields, 2026-06), `LRHUTTTTCAM156S` (CA unemployment, 2026-07), `LRHUTTTTDEM156S`, `LRHUTTTTGBM156S`, `NAEXKP01CAQ657S` (CA real GDP q/q, 2026-Q2), `CLVMNACSCAB1GQDE` (Eurostat DE real GDP, 2026-Q2). **Stale**: `CPALTT01CAM659N`, `CPALTT01DEM659N`, `CPHPTT01GBM659N` end 2025-03; `CPALTT01JPM659N` ends 2021-06. Prefer OECD/Eurostat/WB for non-US CPI.275276---277278## 7. Our World in Data — VERIFIED (CC BY 4.0; cite "Our World in Data" + underlying source from metadata)279280| File | Size | Rows × cols | Years | Notes |281|---|---|---|---|---|282| `https://raw.githubusercontent.com/owid/co2-data/master/owid-co2-data.csv` | 14.4 MB | 50 411 × 79 | 1750–2024 | codebook `owid-co2-codebook.csv` (200) |283| `https://raw.githubusercontent.com/owid/energy-data/master/owid-energy-data.csv` | 9.2 MB | 23 377 × 130 | 1900–2025 | codebook `owid-energy-codebook.csv` (200) |284285- Key columns `country,year,iso_code,population,gdp`. **Aggregates/regions have an empty `iso_code`** (co2: 36 of 254 entities, e.g. `World`, `Europe`, `European Union (27)`, `High-income countries`, `Asia (GCP)`, `International aviation`, `Kuwaiti Oil Fires`; energy: 94 of 314 incl. `Africa (EI)`, `EU (Ember)`, historical `Czechoslovakia`, `East Germany`). **No `OWID_` codes in these two CSVs** (unlike the grapher API) — also `Kosovo` has empty `iso_code`. Filter `iso_code != ""` for countries (then map `OWID_KOS`→`XKX` yourself if you take Kosovo from grapher).286- All requested co2 columns exist: `co2, co2_per_capita, co2_per_gdp, methane, nitrous_oxide, total_ghg, share_global_co2, temperature_change_from_co2, consumption_co2_per_capita, coal_co2, oil_co2, gas_co2, cumulative_co2, land_use_change_co2` (+ `co2_including_luc`, `cement_co2`, `flaring_co2`, `trade_co2_share`…). CAN 2024: co2 533.34 Mt, co2_per_capita 13.42, total_ghg 802.7, methane 115.3, land_use_change_co2 111.9, `consumption_co2_per_capita` empty for 2024 (lags a year).287- All requested energy columns exist: `electricity_generation, renewables_share_elec, solar_share_elec, wind_share_elec, hydro_share_elec, nuclear_share_elec, fossil_share_elec, low_carbon_share_elec, energy_per_capita, energy_per_gdp, primary_energy_consumption, per_capita_electricity, net_elec_imports_share_demand, carbon_intensity_elec`. CAN 2025: generation 652.4 TWh, renewables 63.9 %, hydro 52.8 %, nuclear 13.1 %, fossil 23.0 %, per_capita_electricity 16 259 kWh, carbon_intensity_elec 190.7 gCO2/kWh; `energy_per_capita` empty for 2025 (Energy Institute data lags Ember).288- Missing values = empty string. Units per codebook (co2 in Mt; shares in %; energy_per_capita kWh/person).289290Grapher API: `https://ourworldindata.org/grapher/life-expectancy.csv?v=1&csvType=full&useColumnShortNames=true` → 605 KB, header `entity,code,year,life_expectancy_0`; 21 564 rows; aggregates carry **`OWID_` codes** (`OWID_WRL, OWID_EUR, OWID_HIC, OWID_KOS, OWID_USS…`, 765 rows). `csvType=filtered&country=CAN~USA&time=2020..latest` works (`Canada,CAN,2022,81.2493`). Sibling `….metadata.json?…` → `{"chart":{"title","citation":"Riley (2005); Zijdeman et al. (2015); HMD (2025); UN WPP (2024)"},"columns":{"life_expectancy_0":{"titleShort","unit":"years","lastUpdated":"2025-10-22","citationShort":…}}}` — use `columns.*.lastUpdated` for freshness and `citationShort` for attribution.291292---293294## 8. UN and others295296**UN WPP Data Portal API** (`https://population.un.org/dataportalapi/api/v1/`): metadata endpoints `/indicators`, `/locations` answer **200 without a token**, but every data endpoint (`/data/indicators/49/locations/124/start/2023/end/2024`) → **HTTP 401, `www-authenticate: Bearer`** — token required (confirmed). Token-free fallback: bulk CSV `https://population.un.org/wpp/assets/Excel%20Files/1_Indicator%20(Standard)/CSV_FILES/WPP2024_Demographic_Indicators_Medium.csv.gz` (200, 16.6 MB gz, includes ISO3 + projections to 2100).297298**UN Comtrade**: `https://comtradeapi.un.org/data/v1/get/C/A/HS?reporterCode=124&period=2023&partnerCode=0&cmdCode=TOTAL&flowCode=X` → **401 "missing subscription key"** (confirmed). Free preview **works without key**: `https://comtradeapi.un.org/public/v1/preview/C/A/HS?reporterCode=124&period=2023&partnerCode=0&cmdCode=TOTAL&flowCode=X` → `{"count":12,"data":[{"period":"2023","flowCode":"X","cmdCode":"TOTAL","primaryValue":224462800586.53,…}]}` (≤ 500 records, `reporterISO` null in preview, M49 numeric codes; rate-limited).299300**BIS Data Portal SDMX v2** (`https://stats.bis.org/api/v2/`, no key). CSV via `?format=csv`; JSON needs header `Accept: application/vnd.sdmx.data+json` (`format=json` → 406). Country dim **ISO2** (`CA`, `US`, `XM` euro area, `4T`/`5R`/`XW` aggregates). Structures: `/structure/dataflow/BIS/WS_CBPOL/1.0?references=all` (`Accept: application/vnd.sdmx.structure+json`).301- Policy rates `WS_CBPOL`, key `FREQ.REF_AREA`: `GET /data/dataflow/BIS/WS_CBPOL/1.0/M.CA+US?startPeriod=2026-06&format=csv` →302  `FREQ,REF_AREA,UNIT_MEASURE,…,TIME_PERIOD,OBS_VALUE,OBS_STATUS` → `M,CA,368,…,2026-08,2.25,A` / `M,US,368,…,2026-08,3.625,A` (unit 368 = per cent per year; US = midpoint of target range). All countries: `/M.?startPeriod=2026-08` → 34 areas (AU BR CA CH CL CN CO CZ DK GB HK HU ID IS JP KW MA MK MX MY NO NZ PE PH PL RO RS RU SE TH TR US XM ZA). Daily also available (`D.`).303- Property prices `WS_SPP`, key `FREQ.REF_AREA.VALUE.UNIT_MEASURE` (VALUE `N` nominal / `R` real; UNIT `628` index 2010=100, `771` y/y %): `GET /data/dataflow/BIS/WS_SPP/1.0/Q.CA+US.R.628?startPeriod=2025-Q1&format=csv` → `Q,US,R,628,…,2025-Q1,159.7398,A`. All countries latest: `/Q..N+R.628?startPeriod=2026-Q1` → 59 areas, 118 rows. Quoted `TITLE/COMPILATION` fields contain commas — use a real CSV parser.304305**ILOSTAT SDMX** (`https://sdmx.ilo.org/rest/`, no key, `cache-control: no-store`). The id `DF_UNE_DEAP_SEX_AGE_RT_A` **does not exist** (404 "Could not find Dataflow"); current flows (from `/dataflow/ILO`, 1 212 flows): **`DF_UNE_DEAP_SEX_AGE_RT`** (survey-based, annual+quarterly) and **`DF_UNE_2EAP_SEX_AGE_RT`** ("ILO modelled estimates, Nov. 2025", incl. projections). Dims `REF_AREA.FREQ.MEASURE.SEX.AGE`.306`GET /data/ILO,DF_UNE_DEAP_SEX_AGE_RT/.A..SEX_T.AGE_YTHADULT_YGE15?startPeriod=2024&format=csv` → 537 rows, 200 areas:307`DATAFLOW,REF_AREA,FREQ,MEASURE,SEX,AGE,TIME_PERIOD,OBS_VALUE,OBS_STATUS,…,SOURCE` → `ILO:DF_UNE_DEAP_SEX_AGE_RT(1.0),CAN,A,UNE_DEAP_RT,SEX_T,AGE_YTHADULT_YGE15,2023,5.389,,RT,PT,0,LFS - Labour Force Survey,…`.308Modelled: `/data/ILO,DF_UNE_2EAP_SEX_AGE_RT/.A..SEX_T.AGE_YTHADULT_YGE15?startPeriod=2025` → 271 areas, years 2025–2027 (**2026–2027 are projections**; CAN 2025 6.907 = WB SL.UEM.TOTL.ZS 2025). Age codes: `AGE_YTHADULT_YGE15` (15+), `AGE_YTHADULT_Y15-64`, `AGE_YTHADULT_Y15-24` youth.309310---311312## Cross-source notes for connectors313- Prefer ISO3 as the canonical key. Convert: Eurostat `EL→GR`, `UK→GB` (ISO2→ISO3 table); BIS ISO2→ISO3; OWID `OWID_KOS→XKX`, drop other `OWID_*`; WB `XKX` Kosovo exists; IMF uses `KOS`; WHO uses ISO3 but no Kosovo.314- Forecast flags: IMF `TIME_PERIOD > LATEST_ACTUAL_ANNUAL_DATA`; ILO modelled `year > 2025`; WHO tobacco has 2030 values; Eurostat status `p`/`e`; FRED incomplete-year aggregates return `"."`.315- Freshness fields: WB `lastupdated` (meta) and `/source/2.lastupdated`; IMF CSV `UPDATE_DATE`; OECD none per row (HTTP `last-modified` absent) → store fetch date; Eurostat `updated`; WHO `Date`; FRED `last_updated`; OWID metadata `columns.*.lastUpdated`, GitHub `etag`.316- Parsing hazards: WB empty `countryiso3code` for 5 income aggregates; FRED control chars in `notes`; OECD/BIS labels with commas; OECD jsondata descending time; Eurostat sparse index arithmetic.317