Request
We want to build a new adaptor for OpenStreetMap (OSM), the open, community-maintained map of the world (ODbL licensed). Governments increasingly use OSM as a source of truth (or a cross-check) for health facilities, schools, roads, admin boundaries and addresses, but getting that data into their registries, HMIS and planning tools is usually a manual export.
OSM is not one API but a family of services. This adaptor should wrap the three that matter for integration:
| Service |
What it's for |
Auth |
Default base URL |
| Overpass API |
Read-only queries over OSM data (by tag, area, bbox, "changed since") |
None |
https://overpass-api.de/api/interpreter |
| OSM API v0.6 |
Read elements/changesets; create Notes (bug reports for mappers) |
OAuth 2.0 Bearer (only for writes) |
https://api.openstreetmap.org/api/0.6 |
| Nominatim |
Geocoding / reverse geocoding |
None |
No default (see 6 below) |
Why now / driving use case: Jack is giving a talk with live demo at State of the Map LATAM 2026 (Open Source Tech Talks, Tue 27 Oct 2026, Mexico City). The organiser (DPGA) asked specifically for "how a government team could connect OSM data with its other systems using OpenFn". We need a working v1 by ~Fri 23 Oct to build and record the demo.
Demo workflows (to validate the adaptor against)
- Scheduled "latest cut" of OSM to downstream systems (primary demo). Cron-triggered workflow (daily for the demo; weekly is a sensible default for registries) that:
- queries Overpass for health facilities in an area (e.g.
amenity~"hospital|clinic|doctors" / healthcare=* in CDMX), only elements changed since the last run (newer: filter with a cursor stored in state);
- converts to GeoJSON and maps to the format each downstream system needs (e.g. DHIS2 org units with coordinates via
@openfn/language-dhis2, a FHIR Location, or a CSV/GeoJSON drop for a planning tool);
- upserts into the target and stores the new cursor.
Incremental beats a full re-export: smaller payloads, kinder to public Overpass, and naturally gives a "what changed this week" log.
- Registry vs OSM gap check, feeding back to the community. Compare a government facility list against OSM (match on
ref/name within a radius). For facilities missing or mismatched in OSM, create an OSM Note at the location rather than editing the map directly. This respects the Automated Edits code of conduct and lets local mappers verify. Good story for a SotM audience: governments give back, not just take.
- Geocode / enrich incoming records (optional, only with a self-hosted or commercial Nominatim). E.g. reverse geocode GPS points from an ODK/Kobo submission to municipality/state before loading into a registry.
To start, this adaptor should:
- Configuration & auth. All base URLs overridable (so users can point at self-hosted Overpass/Nominatim, regional instances, or the dev sandbox). Optional OAuth 2.0
access_token sent as Authorization: Bearer ... to the OSM API only. Reads must work with no credentials.
- Mandatory
userAgent. OSMF policies require an identifying User-Agent (stock library UAs get blocked). Make it required in the config schema and send it on every request.
- Generic HTTP helpers (
request, get, post) scoped to each service, e.g. get('/map', { query: { bbox } }) against the OSM API, so any unwrapped endpoint can be called.
- Overpass:
query(overpassQL, options) posts raw Overpass QL and returns JSON (force [out:json] if not set; expose timeout).
- Convenience helper, e.g.
findFeatures({ tags, bbox | area, newerThan }, options) that builds the QL for the common "these tags, in this place, changed since X" case.
- Handle
429/504 (rate-limited / server busy) with backoff and a clear error; optionally check /api/status before heavy queries.
- OSM API v0.6 (read + Notes):
getElement(type, id, { full }), getElements(type, ids), getMap(bbox) (JSON variants via .json endpoints).
listNotes({ bbox, closed }), getNote(id), createNote({ lat, lon, text }), commentNote(id, text).
- Out of scope for v1: creating changesets / editing map data (see Automated Edits policy). Follow-up issue if needed.
- Nominatim:
geocode(query, options) and reverseGeocode({ lat, lon }, options). No default URL: the Nominatim usage policy explicitly says the public API must not be built into or offered by no-code/low-code platforms as a generic geocoding service, and limits use to 1 req/s (4 req/min for scheduled scripts). So: nominatimUrl must be set deliberately by the user, enforce a client-side rate limit, and link the policy in the JSDoc/README.
- GeoJSON helper:
toGeoJSON(osmJson) (e.g. wrapping osmtogeojson) so downstream mapping works with standard geometry.
- Results in
state.data, errors that pass through the server message, and never log the access token.
- README must cover: ODbL attribution/share-alike obligations, Overpass/Nominatim fair-use, and the "use Notes, not edits" pattern.
- Unit tests with mocks for every operation, plus JSDoc examples for each.
Credentials
- Login credentials: No shared account yet.
- Overpass / Nominatim reads: no credentials needed.
- OSM API (Notes, authenticated reads): use the OSM dev sandbox, not production: https://master.apis.dev.openstreetmap.org/ (alias
api06.dev.openstreetmap.org). Its database is separate from live OSM, so create a fresh account there, then register an OAuth 2 app (Settings > OAuth 2 applications) with scopes read_prefs, write_notes. Save the login, client ID/secret and access token in LastPass as OSM Dev Sandbox - Adaptor Dev. Please don't post credentials here.
- Only once tests pass on the sandbox should we create a production OAuth app (and only
write_notes, not write_api).
- Test record(s):
- Overpass: query live data with a small bbox around central CDMX (e.g. Centro Histórico,
19.42,-99.15,19.44,-99.12). Capture real responses as test fixtures.
- Sandbox: it's mostly empty. Copy a small CDMX area into it with osm_to_sandbox, then create/comment test Notes there.
- Nominatim (optional): run locally via Docker (mediagis/nominatim-docker) loaded with the Geofabrik Mexico extract. Note there is no Overpass on the dev sandbox; for fully offline CI, mock Overpass or run Overpass API Docker on a small extract.
- Authentication method(s): OAuth 2.0 (Authorization Code / PKCE). Access tokens currently don't expire, so a one-time token stored in the credential is fine for v1. Prod:
https://www.openstreetmap.org/oauth2/authorize and /oauth2/token. Sandbox: same paths on master.apis.dev.openstreetmap.org. OAuth docs
- Suggested
configuration-schema.json: userAgent (required), access_token (optional, sensitive), apiUrl, overpassUrl (optional, defaults above), nominatimUrl (optional, no default).
Sample Code
// Workflow 1: weekly/daily "latest cut" of health facilities in CDMX
query(`
[out:json][timeout:90];
area["name"="Ciudad de México"]["admin_level"="4"]->.cdmx;
nwr["amenity"~"hospital|clinic|doctors"](area.cdmx)(newer:"${$.lastRun ?? '2026-01-01T00:00:00Z'}");
out center tags;
`);
fn(state => {
state.facilities = toGeoJSON(state.data).features;
state.lastRun = new Date().toISOString();
return state;
});
// ...then map state.facilities into DHIS2 / FHIR / CSV in the next step
// Same thing via the convenience helper
findFeatures(
{ tags: { amenity: ['hospital', 'clinic', 'doctors'] }, area: 'Ciudad de México', newerThan: $.lastRun },
{ geojson: true }
);
// Workflow 2: flag a registry facility missing from OSM as a Note
createNote({
lat: 19.4326,
lon: -99.1332,
text: 'Government health registry lists "Centro de Salud X" (CLUES ABC123) here, not found in OSM. Please verify. #OpenFn',
});
// Workflow 3 (self-hosted Nominatim only)
reverseGeocode({ lat: $.data.gps.lat, lon: $.data.gps.lon }, { zoom: 10 });
// generic escape hatch
get('/map.json', { query: { bbox: '-99.14,19.43,-99.13,19.44' } });
Resources
- OSM developer overview: https://wiki.openstreetmap.org/wiki/API and Developer FAQ
- OSM API v0.6: https://wiki.openstreetmap.org/wiki/API_v0.6 (Notes section: https://wiki.openstreetmap.org/wiki/API_v0.6#Map_Notes_API)
- OAuth 2.0: https://wiki.openstreetmap.org/wiki/OAuth, server metadata: https://www.openstreetmap.org/.well-known/oauth-authorization-server
- Dev sandbox: https://wiki.openstreetmap.org/wiki/Sandbox_for_editing, list of dev APIs: https://apis.dev.openstreetmap.org/
- Overpass API: https://wiki.openstreetmap.org/wiki/Overpass_API, Overpass QL reference, user manual, public instances list (same page), and overpass turbo for building/testing queries
- Nominatim: API docs https://nominatim.org/release-docs/latest/api/Overview/, usage policy https://operations.osmfoundation.org/policies/nominatim/
- Policies: Automated Edits code of conduct, ODbL / copyright, Attribution guidelines
- Data extracts (bulk alternative to Overpass): Geofabrik downloads, planet.osm
- Libraries:
osmtogeojson (OSM/Overpass JSON to GeoJSON)
- Event context: https://www.osmlatam.org/sotm/2026-es/
Logo Links
Request
We want to build a new adaptor for OpenStreetMap (OSM), the open, community-maintained map of the world (ODbL licensed). Governments increasingly use OSM as a source of truth (or a cross-check) for health facilities, schools, roads, admin boundaries and addresses, but getting that data into their registries, HMIS and planning tools is usually a manual export.
OSM is not one API but a family of services. This adaptor should wrap the three that matter for integration:
https://overpass-api.de/api/interpreterhttps://api.openstreetmap.org/api/0.6Why now / driving use case: Jack is giving a talk with live demo at State of the Map LATAM 2026 (Open Source Tech Talks, Tue 27 Oct 2026, Mexico City). The organiser (DPGA) asked specifically for "how a government team could connect OSM data with its other systems using OpenFn". We need a working v1 by ~Fri 23 Oct to build and record the demo.
Demo workflows (to validate the adaptor against)
amenity~"hospital|clinic|doctors"/healthcare=*in CDMX), only elements changed since the last run (newer:filter with a cursor stored in state);@openfn/language-dhis2, a FHIRLocation, or a CSV/GeoJSON drop for a planning tool);Incremental beats a full re-export: smaller payloads, kinder to public Overpass, and naturally gives a "what changed this week" log.
ref/name within a radius). For facilities missing or mismatched in OSM, create an OSM Note at the location rather than editing the map directly. This respects the Automated Edits code of conduct and lets local mappers verify. Good story for a SotM audience: governments give back, not just take.To start, this adaptor should:
access_tokensent asAuthorization: Bearer ...to the OSM API only. Reads must work with no credentials.userAgent. OSMF policies require an identifying User-Agent (stock library UAs get blocked). Make it required in the config schema and send it on every request.request,get,post) scoped to each service, e.g.get('/map', { query: { bbox } })against the OSM API, so any unwrapped endpoint can be called.query(overpassQL, options)posts raw Overpass QL and returns JSON (force[out:json]if not set; exposetimeout).findFeatures({ tags, bbox | area, newerThan }, options)that builds the QL for the common "these tags, in this place, changed since X" case.429/504(rate-limited / server busy) with backoff and a clear error; optionally check/api/statusbefore heavy queries.getElement(type, id, { full }),getElements(type, ids),getMap(bbox)(JSON variants via.jsonendpoints).listNotes({ bbox, closed }),getNote(id),createNote({ lat, lon, text }),commentNote(id, text).geocode(query, options)andreverseGeocode({ lat, lon }, options). No default URL: the Nominatim usage policy explicitly says the public API must not be built into or offered by no-code/low-code platforms as a generic geocoding service, and limits use to 1 req/s (4 req/min for scheduled scripts). So:nominatimUrlmust be set deliberately by the user, enforce a client-side rate limit, and link the policy in the JSDoc/README.toGeoJSON(osmJson)(e.g. wrappingosmtogeojson) so downstream mapping works with standard geometry.state.data, errors that pass through the server message, and never log the access token.Credentials
api06.dev.openstreetmap.org). Its database is separate from live OSM, so create a fresh account there, then register an OAuth 2 app (Settings > OAuth 2 applications) with scopesread_prefs,write_notes. Save the login, client ID/secret and access token in LastPass asOSM Dev Sandbox - Adaptor Dev. Please don't post credentials here.write_notes, notwrite_api).19.42,-99.15,19.44,-99.12). Capture real responses as test fixtures.https://www.openstreetmap.org/oauth2/authorizeand/oauth2/token. Sandbox: same paths onmaster.apis.dev.openstreetmap.org. OAuth docsconfiguration-schema.json:userAgent(required),access_token(optional, sensitive),apiUrl,overpassUrl(optional, defaults above),nominatimUrl(optional, no default).Sample Code
Resources
osmtogeojson(OSM/Overpass JSON to GeoJSON)Logo Links