# Atlas API and MCP World in Layers gives your software and your AI agent the same data the atlas shows: weather and air-quality forecasts, reanalysis history, sea temperature and waves, seasonal climate, fire detections, earthquakes, volcano records and Earth's magnetic field. You reach it in two ways that return identical payloads: - **MCP** at `https://worldinlayers.com/mcp`, for Claude Code, Cursor, VS Code, Gemini CLI and the Anthropic and OpenAI APIs. - **REST** at `https://worldinlayers.com/api/v1/agent/`, for scripts, notebooks and your own services. JSON by default, CSV for lists and series. The service returns **data only**. It does not write answers; your agent does the reasoning. Every number arrives with its units, data kind, valid time, provider and a public link that reproduces it, so a person can check what the agent said. ## Who it is for The job is the same for everyone: trustworthy numbers about a place and a time, where they came from, and a link a person can open to check them. The examples below use REST so you can see the exact call; an agent connected over MCP makes the same calls. **Recorded responses.** Every response shown on this page was recorded from a local run on the date given beside it. Responses for the three environmental examples (Portugal's gusts, the earthquakes and the Brno forecast) depend on live forecast and catalogue snapshots and will be added after the first deployment. In every example, `$ATLAS_API_KEY` holds your key. ### Newsrooms and data journalists _How much of Portugal sees gusts of 60 km/h or more today?_ One call returns the area-weighted mean, the minimum and maximum with the nearest named place (none over open ocean far from land), and the share of land at or above the threshold, across the frames of the local day. ```sh curl -s "https://worldinlayers.com/api/v1/agent/atlas_area_stats?layer=gusts&country=PT&time=now&period=day&tz=Europe/Lisbon&threshold=60" \ -H "Authorization: Bearer $ATLAS_API_KEY" ``` `period=day` costs 10 units per forecast frame used, at most 40. The `method` field describes the grid, weights, cells and frames, and `reproduce` lets an editor re-run the same figure while the snapshot is retained. ### Researchers and students _Declination at the Hurbanovo observatory in Slovakia, yearly from 1900 to 2026, as CSV._ ```sh curl -s "https://worldinlayers.com/api/v1/agent/atlas_get_time_series?format=csv" \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"points":[{"lat":47.87,"lon":18.19}],"layers":["magnetism"],"model":"igrf14","start":"1900","end":"2026","samples":127}' ``` Recorded from a local run on 25 October 2026: the header and the first rows of 635 (127 years for each of the five components F, D, I, H and Z, in that order; the declination rows are `magnetism:D`). `predictive` is `false` for the model years up to 2025 and `true` only on the 2026 rows, where IGRF-14 extrapolates; `status` is `ok` on every answered row: ```csv place,place_id,lat,lon,layer,time,value,units,provider,data_kind,preliminary,stale,predictive,snapshot_version,source_url,status,error "47.8700, 18.1900",,47.87,18.19,magnetism:F,1900.0,45850,nT,IGRF-14 (NOAA NCEI / IAGA),model,false,,false,,https://worldinlayers.com/api/v1/timeseries?lat=47.87&lon=18.19&model=igrf14&start=1900.0&end=2026.0&samples=127,ok, "47.8700, 18.1900",,47.87,18.19,magnetism:F,1901.0,45838,nT,IGRF-14 (NOAA NCEI / IAGA),model,false,,false,,https://worldinlayers.com/api/v1/timeseries?lat=47.87&lon=18.19&model=igrf14&start=1900.0&end=2026.0&samples=127,ok, "47.8700, 18.1900",,47.87,18.19,magnetism:F,1902.0,45827,nT,IGRF-14 (NOAA NCEI / IAGA),model,false,,false,,https://worldinlayers.com/api/v1/timeseries?lat=47.87&lon=18.19&model=igrf14&start=1900.0&end=2026.0&samples=127,ok, … "47.8700, 18.1900",,47.87,18.19,magnetism:D,1900.0,-7.36,degrees,IGRF-14 (NOAA NCEI / IAGA),model,false,,false,,https://worldinlayers.com/api/v1/timeseries?lat=47.87&lon=18.19&model=igrf14&start=1900.0&end=2026.0&samples=127,ok, "47.8700, 18.1900",,47.87,18.19,magnetism:D,1901.0,-7.28,degrees,IGRF-14 (NOAA NCEI / IAGA),model,false,,false,,https://worldinlayers.com/api/v1/timeseries?lat=47.87&lon=18.19&model=igrf14&start=1900.0&end=2026.0&samples=127,ok, "47.8700, 18.1900",,47.87,18.19,magnetism:D,1902.0,-7.21,degrees,IGRF-14 (NOAA NCEI / IAGA),model,false,,false,,https://worldinlayers.com/api/v1/timeseries?lat=47.87&lon=18.19&model=igrf14&start=1900.0&end=2026.0&samples=127,ok, … ``` A series costs 2 units per place. Before asking for environmental dates, call `atlas_layer_coverage` to see the archive range and which dates are retained. ### Public sector, NGOs and humanitarian teams _Earthquakes of magnitude 4.5 or more in a box over Greece and western Turkey in the last 30 days, with their USGS event ids._ ```sh curl -s "https://worldinlayers.com/api/v1/agent/atlas_find_events?kind=earthquakes&bbox=19,34,30,42&window=30d&min_magnitude=4.5" \ -H "Authorization: Bearer $ATLAS_API_KEY" ``` Each event carries its USGS id, so you can cross-check it with the source. A page of events costs 1 unit; follow `next_cursor` for more. Add `format=csv` for a table. ### Product developers and hobby projects _A home weather bot: temperature, wind and rain in Brno for the forecast hours, with local times._ ```sh curl -s https://worldinlayers.com/api/v1/agent/atlas_get_time_series \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"points":[{"place":"Brno","place_country":"CZ"}],"layers":["temperature","wind","precipitation"],"tz":"Europe/Prague"}' ``` Two units per place, whatever the number of layers up to 8. The response names the place it resolved (`Brno, CZ`). To pin one place for later calls, look it up once with `atlas_find_place` and send its `place_id` instead of the name. ## Plans and quotas Keys are part of the **Plus** (EUR 9 a month or EUR 79 a year) and **Pro** (EUR 19 a month or EUR 190 a year) plans, plus applicable tax. There is no free tier. See [pricing](https://worldinlayers.com/pricing). Quotas are per account, not per key or per IP address, and reset at 00:00 UTC. | Limit | Plus | Pro | | ---------------------------------------------- | ----- | ------ | | Units per day | 3,000 | 10,000 | | Requests per minute (burst) | 120 | 240 | | Requests running at the same time | 2 | 4 | | Cold archive loads per day (ERA5, OISST, NCEP) | 16 | 16 | | Map cards per day | 10 | 30 | | Places per batch call | 10 | 20 | | API keys per account | 5 | 10 | Calls cost **units**, weighted by the work they cause: | Call | Units | | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | `atlas_find_place`, `atlas_list_layers`, `atlas_layer_coverage`, `atlas_status`, `atlas_my_places`, `atlas_map_link` | 1 | | `atlas_get_point_values` | 1 per place (any number of layers up to 8) | | `atlas_get_magnetic_field` | 1 | | `atlas_get_time_series` | 2 per place | | `atlas_find_events` | 1 per page | | `atlas_area_stats` | 10 (`period: day`: 10 per frame used, at most 40) | | `atlas_japan_hazards` | 1 per place | | Cold archive load, per layer family and date, added to the call that needed it (at most 2 per call) | 25 | | `atlas_make_map_card` with `dry_run: true` | 5 | | `atlas_make_map_card` | 50 | | `atlas_make_map_card` for a magnetic date whose field map is not prepared yet (answers `busy`; at most 5 dates a day) | 5 | A **cold archive load** happens when you ask for a historical date the atlas does not already hold: it fetches that date's map from the ERA5, OISST or NCEP archive. One map serves a family of layers, so a call pays one cold load per layer family and date. The families that share a map are temperature, humidity, feels_like, dew_point and wet_bulb; solar, precipitation, clouds and cape; wind, gusts and pressure; and snow_depth and soil_moisture. Every other layer that can be loaded (sea temperature, waves and each climate layer) is a family of its own. Dates listed as retained by `atlas_layer_coverage` need no cold load. A single call makes at most two: temperature, wind and clouds at one uncached date cost 1 + 2 × 25 = 51 units, and clouds comes back in `unavailable[]` with `quota_exceeded` (reason `cold_load_limit`). Archive loads are shared with everyone who uses the atlas, so one account may make at most **5 an hour and 16 a day**, whatever its plan: a third of the atlas's hourly allowance for the API and half of its daily one. Past them a load is refused with `quota_exceeded` (reason `cold_load_limit`) and `quota` `cold_loads_account_hourly` (`retry_after` runs to the next UTC hour) or `cold_loads_account_share` (until 00:00 UTC). When the atlas's own hourly or daily allowance runs out first, `quota` names that instead. Every response reports what the call cost and what remains today. The same figures are on your account page, and `GET /api/v1/agent/usage` with your key returns today's and this month's usage for your account. ## Getting a key 1. Sign in and open your [account page](https://worldinlayers.com/account). 2. Under **API keys**, choose **Create key** and give it a name you will recognise, such as "laptop Claude Code". 3. Copy the key. **It is shown once.** We store only a hash of it; if you lose it, revoke it and create another. 4. The same section lists each key's first characters, name, creation time, when it was last used and by which client, and today's usage against your plan. 5. **Revoke** stops a key at once. Revoking cannot be undone. Keys start with `wil_`. When a paid period ends, the plan continues for three days while the renewal is processed, and keys keep full access. If the subscription is not restored by then, your keys stay but return `402 plan_required` until it is; the account page still lists them so you can revoke them. Deleting your account deletes its keys. ## Authentication Send the key in the `Authorization` header on every request: ```http Authorization: Bearer wil_… ``` Never put a key in a URL or query string; it would end up in logs and browser history. A key in the URL, in the query string or in the path, is refused with `401`, even next to a valid header, and the hint asks you to revoke it because it may have been logged. Treat a key like a password: keep it in an environment variable or your client's secret store, not in a repository. ### Report a security issue or a leaked key If a key has leaked, for example into a public repository, a log or a shared transcript, first **revoke it** on your [account page](https://worldinlayers.com/account) and create a new one; revoking takes effect on the next request. To report a security issue, or a key of someone else's that you have found, write to the contact in [`/.well-known/security.txt`](https://worldinlayers.com/.well-known/security.txt) (hello@worldinlayers.com). ## Quickstarts Replace `` with your key, or use an environment variable where the client supports one. ### Claude Code ```sh claude mcp add --transport http atlas https://worldinlayers.com/mcp --header "Authorization: Bearer " ``` Then ask, for example, "What are the PM2.5, temperature and sea temperature in Lisbon, Portugal now? Give me a map link." `claude mcp get atlas` prints the stored header, **including the whole key**. Do not run it on a shared screen or in a recorded terminal. To try the server without saving the key in a project's configuration, add it with `--scope local` from a scratch directory. If a key has been shown or logged, revoke it on your account page and create a new one. ### Cursor In `~/.cursor/mcp.json`, or `.cursor/mcp.json` in a project. Cursor reads `ATLAS_API_KEY` from the environment it was started from, so set it in your shell profile or start Cursor from a terminal where it is set: ```json { "mcpServers": { "atlas": { "url": "https://worldinlayers.com/mcp", "headers": { "Authorization": "Bearer ${env:ATLAS_API_KEY}" } } } } ``` ### VS Code In `.vscode/mcp.json`. VS Code asks for the key once and stores it securely: ```json { "inputs": [ { "type": "promptString", "id": "atlas-key", "description": "World in Layers API key", "password": true } ], "servers": { "atlas": { "type": "http", "url": "https://worldinlayers.com/mcp", "headers": { "Authorization": "Bearer ${input:atlas-key}" } } } } ``` ### Gemini CLI ```sh gemini mcp add --transport http -H "Authorization: Bearer " atlas https://worldinlayers.com/mcp ``` ### Anthropic Messages API Claude connects to the server for you through the MCP connector. Pass the key as `authorization_token`: ```sh curl -s https://api.anthropic.com/v1/messages \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "anthropic-beta: mcp-client-2025-11-20" \ -H "content-type: application/json" \ -d '{ "model": "claude-opus-5-5", "max_tokens": 4096, "mcp_servers": [{ "type": "url", "url": "https://worldinlayers.com/mcp", "name": "atlas", "authorization_token": "'"$ATLAS_API_KEY"'" }], "tools": [{ "type": "mcp_toolset", "mcp_server_name": "atlas" }], "messages": [{ "role": "user", "content": "Wind gusts in Porto, Portugal now, with the source of each number." }] }' ``` ### OpenAI Responses API Pass the key as `authorization` on an `mcp` tool: ```sh curl -s https://api.openai.com/v1/responses \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "", "tools": [{ "type": "mcp", "server_label": "atlas", "server_url": "https://worldinlayers.com/mcp", "authorization": "'"$ATLAS_API_KEY"'", "require_approval": "never" }], "input": "Wind gusts in Porto, Portugal now, with the source of each number." }' ``` ### curl and REST ```sh curl -s https://worldinlayers.com/api/v1/agent/atlas_get_point_values \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"points":[{"place":"Lisbon","place_country":"PT"}],"layers":["temperature","pm25","sst"],"time":"now","tz":"Europe/Lisbon"}' ``` Every tool is at `/api/v1/agent/`. Use `POST` with a JSON body for several places and for cards; simple calls also accept `GET` with query parameters (repeat a parameter or separate values with commas for lists). Add `format=csv` to point values, series and events for a table. Point values and series take their places as a list, even for one place: `"points": [{"lat": 47.87, "lon": 18.19}]` or `"points": [{"place": "Brno"}]`. In a JSON body, top-level `lat`, `lon` or `place` are refused as unknown properties. Only `GET` accepts them, as a shorthand for a single place: `?lat=47.87&lon=18.19&layers=temperature`. CSV is UTF-8 without a byte order mark, with CRLF line endings and a header row. Text cells that begin with `=`, `+`, `-`, `@`, a tab or a carriage return are prefixed with a single quote (`'`), so a spreadsheet shows them as text instead of running them as formulas; numbers are written as plain numbers, negative values with their minus sign. The full OpenAPI description is at [`/api/v1/openapi.json`](https://worldinlayers.com/api/v1/openapi.json), and the tool schemas at [`/api/v1/agent/tools`](https://worldinlayers.com/api/v1/agent/tools) (no key needed for either). ### MCP over curl `/mcp` is stateless and answers JSON only (no event stream, no session id), so every request below stands alone. It speaks two protocol versions. Every request needs your key in `Authorization`. Send `Content-Type: application/json` and an `Accept` that includes `application/json`, as the examples do: a request without them is accepted, but a different body type is refused with 415 and an `Accept` without JSON with 406. **Protocol 2025-11-25 and earlier.** Start with `initialize`, then send any request with the negotiated version in `MCP-Protocol-Version`: ```sh curl -s https://worldinlayers.com/mcp \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "MCP-Protocol-Version: 2025-11-25" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}' curl -s https://worldinlayers.com/mcp \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "MCP-Protocol-Version: 2025-11-25" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' ``` A `notifications/initialized` notification (no `id`) is acknowledged with HTTP 202 and can be sent in between; nothing is kept between requests either way. **Protocol 2026-07-28.** There is no `initialize`. Every request carries `params._meta` with `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities` (`io.modelcontextprotocol/clientInfo` is optional), and three headers that must match the body: `MCP-Protocol-Version` (the version in `_meta`), `Mcp-Method` (the method) and, for `tools/call` and `prompts/get`, `Mcp-Name` with `params.name`, for `resources/read` with `params.uri`. A mismatch is refused with HTTP 400 and JSON-RPC error `-32020`. `server/discover` replaces the handshake: ```sh curl -s https://worldinlayers.com/mcp \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "MCP-Protocol-Version: 2026-07-28" \ -H "Mcp-Method: server/discover" \ -d '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' ``` Call a tool: ```sh curl -s https://worldinlayers.com/mcp \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "MCP-Protocol-Version: 2026-07-28" \ -H "Mcp-Method: tools/call" \ -H "Mcp-Name: atlas_get_point_values" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"atlas_get_point_values","arguments":{"points":[{"place":"Lisbon","place_country":"PT"}],"layers":["temperature"]},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' ``` Read a resource: ```sh curl -s https://worldinlayers.com/mcp \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "MCP-Protocol-Version: 2026-07-28" \ -H "Mcp-Method: resources/read" \ -H "Mcp-Name: atlas://layers/temperature" \ -d '{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"atlas://layers/temperature","_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' ``` Get a prompt: ```sh curl -s https://worldinlayers.com/mcp \ -H "Authorization: Bearer $ATLAS_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "MCP-Protocol-Version: 2026-07-28" \ -H "Mcp-Method: prompts/get" \ -H "Mcp-Name: atlas_explain_place" \ -d '{"jsonrpc":"2.0","id":4,"method":"prompts/get","params":{"name":"atlas_explain_place","arguments":{"place":"47.87, 18.19"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' ``` In both versions `tools/call` takes `arguments` as an object; leave it out for a tool without arguments. Any other value, such as `null`, `[]` or `false`, is refused with JSON-RPC error `-32602` before the tool runs, and costs nothing. ### Claude.ai and ChatGPT **Available once sign-in is added.** Claude.ai and ChatGPT connect to remote servers by having you sign in through OAuth; they cannot send a personal key header (Claude.ai only through a limited beta, ChatGPT not at all). Sign-in is planned, not built. ## Tools The live reference on this page lists every parameter, generated from the same registry the server uses. In short: | Tool | Answers | Units | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | | `atlas_find_place` | Which place is this? Names, postcodes and countries in any language, or the nearest places to a coordinate; reports ambiguity with candidates | 1 | | `atlas_list_layers` | What can the atlas read? Layers by group, with units, licence, attribution and history start | 1 | | `atlas_layer_coverage` | Which dates exist for a layer? Current snapshot, archive range and retained dates | 1 | | `atlas_status` | How fresh is each source? Model-run and retrieval times | 1 | | `atlas_get_point_values` | Up to 8 layers at one or more places for one time | 1 per place | | `atlas_get_magnetic_field` | Field strength, declination, inclination and their change at a point and date | 1 | | `atlas_get_time_series` | Up to 8 layers over time at one or more places | 2 per place | | `atlas_find_events` | Earthquakes, fire detections or volcanoes near a place or in a box | 1 per page | | `atlas_area_stats` | Mean, minimum, maximum and share above a threshold over a country, box or circle | 10 (day: up to 40) | | `atlas_japan_hazards` | Official hazard zones, projected population, earthquake shaking probability and nearby official land prices at places in Japan | 1 per place | | `atlas_map_link` | A worldinlayers.com link that opens the same layers, time and place | 1 | | `atlas_my_places` | Your saved places (needs the `places` scope) | 1 | | `atlas_make_map_card` | A shareable map card, marked as made through the API (needs the `cards` scope) | 5 dry run, 50 | Every tool except `atlas_make_map_card` only reads. Cards accept the template titles offered by a dry run, never free text, and cannot include satellite layers. Japan hazard cards show the current editions; a Japan population card shows the year of `time` (2030, 2040, 2050 or 2070; 2050 by default). Repeating a card request with the same `client_request_id` returns the same card free of charge; a request for a card identical to one that already exists returns that card for 5 units and does not count as a new card. (If that earlier card was deleted in the meantime, the repeat answers `busy`, reason `card_replay_gone`, free of charge; retrying makes a new card at the normal price.) Earthquake cards show the latest 7 days of earthquakes of magnitude 4.5 or more. A magnetic field card for a date whose field map has not been calculated yet answers `busy` (reason `magnetic_map_preparing`, `retry_after` 15) and costs 5 units while the map is prepared; retry with the same arguments, which costs nothing more until the map is ready and then the card's 50 units. Each account may start at most 5 such maps a day; after that the call is refused with `quota_exceeded` (`quota: magnetic_preparations`) until 00:00 UTC, free of charge. A dry run for such a date queues nothing and answers `not_available` (reason `magnetic_map_not_prepared`), also free. `atlas_find_events` refuses an argument its `kind` does not use, with `invalid_input`: `window` and `min_magnitude` apply to earthquakes only, `start` and `end` to earthquakes and fires. Volcano rows give the latest significant eruption as `time` when the catalogue dates it to the day (otherwise `time` is empty) and, around a point, the distance in `distance_km`. `atlas_map_link` refuses a time that any of its layers cannot show, a future time more than 3 hours after its forecast's last frame: `outside_snapshot` (reason `outside_forecast`); with several layers, the error's `layer` field names the one that cannot. Over MCP the server also offers two prompts, `atlas_explain_place` and `atlas_compare_places`, which carry the house style (cite every number, name the data kind, no verdicts, end with a map link), and resources (`atlas://guide`, `atlas://layers`, `atlas://layers/{id}`, `atlas://attribution`) so your agent can read the layer notes and licences once instead of asking every turn. ## Units, time and data kinds ### Units Metric only, exactly as the atlas shows them: °C, %, km/h, hPa, mm/h, mm/day, J/kg, cm, m³/m³, W/m², UV index, µg/m³, aerosol optical depth at 550 nm, m, MW (fire radiative power), magnitude, nT, nT/year and degrees. Every value names its unit; convert on your side if you need to. ### Time - All times are ISO 8601 and **UTC** unless they carry an offset. - `time` accepts: - `now`; - a date, `2026-10-23`, meaning 12:00 UTC, or local noon when you pass `tz`; - a date and time, `2026-10-23T15:00Z` or `2026-10-23T17:00+02:00`; - for the seasonal climate layers, a month `01`–`12` (the 1991–2020 average), or `YYYY-MM` for one past month. - `tz` takes an IANA time zone such as `Europe/Lisbon`. With it, rows also carry `local_time`, and `period: day` in area statistics means that place's local day. - `start` and `end` of series and event searches are read against the current snapshot: a range that runs past its first or last frame is answered for the part inside it, with a note naming both ranges; a range wholly outside it is refused (`outside_snapshot` for events, `not_available` for series). ### Places and countries Places are coordinates (`lat` and `lon`), names (`place`) or `place_id`s from `atlas_find_place`. Give each place **one way**: `place` with `lat`/`lon`, `place` with `place_id`, `place_id` with `lat`/`lon`, and `place_country` without `place` are refused with `invalid_input` (reason `conflicting_place`). A `place_id` names exactly one place. A name resolves like this: - **The largest clear match wins.** A name shared by several places resolves to the largest clear match: a capital with twice, or a place of at least 50,000 people with five times, the population of the next namesake elsewhere (Lisbon, Portugal over the Lisbons in the United States). The others come back in `candidates[]`, each with its `place_id`, region, country, `match` and `population`, so your agent can mention them or choose another. - **Local names** such as Lisboa, Wien, München or Roma resolve as well as the English ones, but an alternate name never beats a place bearing the name itself when `place_country` narrows it, nor a namesake of 50,000 people or more. - **No clear match returns `ambiguous_place`** with the candidates and their `place_id`s (Springfield, for example). - **Partial matches never resolve silently.** A name that only starts with or contains your text returns `ambiguous_place` with the closest names, never one of them. Common names exist in many countries, so add an ISO 3166-1 alpha-2 code to narrow one: `place: Porto` with `place_country: PT`. Every tool that takes `place` accepts `place_country`, and so does each item of `points[]`. `country` means something else and exists in two tools only: in `atlas_find_place` it narrows the `query`, and in `atlas_area_stats` it is the area itself (`country: PT` gives statistics over all of Portugal; there `place_country` narrows the name of the place at the centre of a circle). - `valid_time` is the UTC time a value is valid for; a count of fire detections gives the window it counted as an interval, `2026-10-21T11:00:00Z/2026-10-22T11:00:00Z`. In the detailed format its `label` is "Active fire detections in the snapshot window" and its `time_label` reads "Detections from 2026-10-21T11:00:00Z to 2026-10-22T11:00:00Z", because the newest snapshot may have ended up to a day before you ask. Gridded layers come in frames (forecast hours, analysis days); when the frame used is not exactly the time you asked for, `offset_minutes` says how far apart they are, to the minute, and from 3 hours apart a note names the time you asked for, the frame's time and the distance, written like "(2 days 1 h 40 min earlier)" or "(3 h 20 min later)". The atlas never picks a nearby frame without saying so, and never swaps a forecast in for a missing historical value. - The archive trails the present by a few days and a new forecast run drops the hours before it, so a recent time can fall between the two. Then the answer is `not_available` (reason `no_data`) with a message naming both edges, for example "the archive runs through 2026-10-19 and the current forecast starts at 2026-10-25T12:00:00Z", and the error's `gap` object holds `archive_end` and `forecast_start`. When an earlier forecast snapshot that is still retained holds the time, `gap.snapshot_version` names it and the hint tells you to send it as `snapshot_version`. ### Data kinds Every value names one of these: | Data kind | Meaning | Examples | | ---------------------- | --------------------------------------------------------------------- | ---------------------------------------------------- | | `forecast` | A model's prediction for a future or current time | NOAA GFS weather, FMI SILAM air quality, NOAA CPC UV | | `analysis` | A best estimate of a past day from observations, on a grid | NOAA OISST sea surface temperature | | `reanalysis` | A consistent reconstruction of the past from observations and a model | Copernicus ERA5, CAMS EAC4, NCEP/NCAR | | `observation` | Something a satellite or network detected or recorded | NASA FIRMS fire detections, USGS earthquakes, OMI UV | | `climatology` | A long-term average | 1991–2020 monthly temperature, rain and humidity | | `model` | A value computed from a published model within its validity period | IGRF-14 and other magnetic field models | | `official_designation` | An official zone under Japanese law; a scenario, not a prediction | Japan hazard zones (MLIT KSJ) | | `official_projection` | An official projection by a government agency | Japan's residents per 1 km mesh (MLIT KSJ) | Magnetic values are always `model` on the API. For dates beyond a model's main-field epoch they also carry `predictive: true`: they extrapolate the model's predicted secular variation (for IGRF-14 and WMM, dates after 2025). Dates outside a model's published validity are refused, never extrapolated further. The example below, for 24 October 2026, is one. Values may also be marked `preliminary` (recent ERA5T or OISST days, recent earthquake solutions, near-real-time fire detections), which the source can still revise. ## The response envelope Every tool returns the same envelope. This is a recorded response, from a local run on 24 October 2026, to the magnetic field at the Hurbanovo observatory in Slovakia: ```sh curl -s "https://worldinlayers.com/api/v1/agent/atlas_get_magnetic_field?lat=47.87&lon=18.19&date=2026-10-24" \ -H "Authorization: Bearer $ATLAS_API_KEY" ``` ```json { "ok": true, "tool": "atlas_get_magnetic_field", "data": { "point": { "lat": 47.87, "lon": 18.19, "name": "47.8700, 18.1900", "altitude_km": 0.0 }, "model": { "id": "igrf14", "version": "IGRF-14", "kind": "model", "attribution": "NOAA NCEI / IAGA", "uncertainty": "Model estimates; local and external fields are not fully represented.", "valid_from": "1900-01-01", "valid_to": "2030-01-01", "predictive_from": "2025-01-01", "predictive": true }, "date": "2026-10-24", "columns": ["quantity", "value", "units", "valid_time", "cite"], "rows": [ ["Total field intensity F · IGRF-14", 49246, "nT", "2026-10-24", "c59a259-1"], ["Declination D (east positive) · IGRF-14", 5.69, "degrees", "2026-10-24", "c59a259-1"], ["Inclination I (down positive) · IGRF-14", 64.64, "degrees", "2026-10-24", "c59a259-1"], ["Horizontal intensity H · IGRF-14", 21089, "nT", "2026-10-24", "c59a259-1"], ["Vertical intensity Z (down positive) · IGRF-14", 44502, "nT", "2026-10-24", "c59a259-1"], ["Yearly change of F at 2026-10-24 · IGRF-14", 50.4, "nT/year", "2026-10-24", "c59a259-2"] ] }, "citations": [ { "id": "c59a259-1", "layer": "magnetism", "provider": "IGRF-14 (NOAA NCEI / IAGA)", "data_kind": "model", "preliminary": false, "source_url": "https://worldinlayers.com/api/v1/point?lat=47.87&lon=18.19&model=igrf14&date=2026-10-24", "model": "igrf14", "predictive": true }, { "id": "c59a259-2", "layer": "magnetism", "provider": "IGRF-14", "data_kind": "model", "preliminary": false, "source_url": "https://worldinlayers.com/api/v1/point?lat=47.87&lon=18.19&model=igrf14&date=2026-10-24", "model": "igrf14", "predictive": true } ], "attribution": [ "Magnetic field: IGRF-14, International Association of Geomagnetism and Aeronomy (IAGA); coefficients distributed by NOAA NCEI." ], "notes": [ "Model values, not certified navigation or aeronautical guidance. Official charts and national survey values take precedence; local anomalies from rocks, buildings or vehicles are not included." ], "links": { "map": "https://worldinlayers.com/magnetic-field?date=2026-10-24¢er=18.1900%2C47.8700&zoom=6.00&places=%5B%7B%22id%22%3A%22ask-47.8700-18.1900%22%2C%22name%22%3A%2247.8700%2C+18.1900%22%2C%22latitude%22%3A47.87%2C%22longitude%22%3A18.19%2C%22kind%22%3A%22place%22%7D%5D" }, "usage": { "units": 1, "units_today": 1193, "units_limit": 10000, "cold_loads_today": 1, "cold_loads_limit": 16, "cards_today": 0, "cards_limit": 30 } } ``` Magnetic models are files held by the atlas, so their citations have no `snapshot_version` or `retained_until`; values from forecasts, analyses and archives carry both. `usage` shows the limits of the plan the key belongs to (Pro here). | Field | What it holds | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ok`, `tool` | Whether the call succeeded, and which tool answered. | | `data` | The answer. By default (`response_format: concise`) a table: `columns` and `rows`, with a `cite` id on each row. `response_format: detailed` returns full objects instead, such as `points[]{place, values[], unavailable[]}`. | | `citations[]` | One entry per distinct source (in the concise format, one per layer and snapshot): `data_kind`, `provider`, `snapshot_version` (the data snapshot the value came from), `retained_until` (how long that snapshot is kept), and `source_url`, an absolute public link that returns the same value while the snapshot is retained (or `source_url_template`, filled from each row, when the rows were read at different places). Derived figures such as area means and shares carry `reproduce{tool, args, snapshot_version}` instead of a link. | | `attribution[]` | The credit line for each provider in the response, once each. Show it wherever you publish the numbers; see [Attribution and citing](https://worldinlayers.com/developers.html#attribution-and-citing). | | `notes[]` | Caveats you should pass on: preliminary data, coastal points read from the nearest open water, a frame 3 hours or more from the requested time, a range cut to the snapshot, a local day that daily area statistics cover only in part, and the reminder that the atlas shows data, not verdicts. Every frame offset is also in its row's `offset_minutes`. | | `links.map` | A worldinlayers.com link that opens this layer, time and place, so a person can look. A layer of `atlas_get_point_values` that had no value for the requested time is left out of it, and a note says so. | | `usage` | Units this call cost, units used today and your daily limit, and the same for cold archive loads. Over MCP the same object is in the result's `_meta.usage`. | Citation ids look like `c3f9a2b-1`: a random six-hex-digit prefix for the call and a number, so they are unique within one response and differ between responses. Cite them exactly as returned, and when an answer combines several responses, keep each id together with its `source_url`. The concise format keeps citations short: there is **one citation per layer and snapshot**, so the rows of one layer share its id. In a series or a batch of places, every row of a layer cites the same id, not one id per row (a series whose days mix final and preliminary values has two, one for each, and so has a magnetic series that mixes model and predictive years). When the rows citing an id were read at different coordinates or times, or are different events, the citation carries `source_url_template` instead of `source_url` (earthquakes also `provider_url_template` instead of `provider_url`), with `{lat}`, `{lon}`, `{id}` and `{frame}` placeholders. Fill them from the row's own `lat`, `lon` and `id` cells, and `{frame}` from its `frame` cell (or, when the table has no `frame` column, its `time`), to get the exact link for that row. The concise tables have these columns: - point values: `place`, `lat`, `lon`, `layer`, `value`, `units`, `data_kind`, `valid_time`, `local_time` (with `tz`), `offset_minutes`, `cite`; - series: `place`, `place_id`, `lat`, `lon`, `layer`, `time`, `frame` (only when a frame's id differs from its time, as for daily sea temperature, read from the 00:00 frame and valid at 12:00), `local_time` (with `tz`), `value`, `units`, `cite`. Point values and series also return `places[]`, the places as resolved, in the order you sent them. A place that did not resolve keeps what you sent (`place`, `place_country`, `place_id`, or `lat` and `lon`) and adds `status`, its error code such as `invalid_place`; its values are in `unavailable[]`. `lat` and `lon` are where the value was read, which for a sea layer at a coastal place is the nearest open water. REST CSV (`format=csv`) replaces `cite` with the citation's `provider`, `data_kind`, `preliminary` (`true` or `false`), `stale` (`true` while the source's refresh is overdue, else empty), `predictive` (`true` or `false` for magnetic values, else empty; per row, so a magnetic series that runs past a model's main-field epoch has two citations, one for the model years and one for the predictive years), `snapshot_version` and `source_url` (columns the table already has are not repeated), and fills the template, so every CSV row has its exact `source_url`. Event CSVs add the provider's own page, `provider_url`, after it. Point-value and series CSVs end with two more columns, `status` (`ok`, or the error code such as `no_coverage`) and `error` (the message), and add one row with an empty value for each layer or place that could not be answered (with its place and layer; a place that did not resolve is named as you sent it), so a partial export cannot pass for a complete one; JSON lists those in `unavailable[]` instead, with `retry_after` when a retry may succeed. `response_format: detailed` is unchanged: every value has its own citation with its own `source_url`. Derived values (area statistics, series, event counts, volcano distances) also carry `reproduce`: the call, with resolved times, coordinates and `snapshot_version`, that returns them again while the snapshot is retained. It covers only that citation's layers: a series of temperature and PM2.5 gives the weather citation a call for temperature and the air-quality citation one for PM2.5. The volcano catalogue keeps only its current version, which each volcano citation states in `retention`. An earthquake count also carries `provider_url`: the USGS FDSN query for the same window, area and minimum magnitude, to check the count against USGS's live catalogue (which revises automatic solutions, so its answer can change later; `reproduce` replays the atlas's snapshot). Rows and citations are in a stable order. A JSON answer is at most 60,000 characters, about 20,000 tokens, so an MCP result stays under the 25,000-token default limit of common clients such as Claude Code. In the concise format that is plenty: 20 places × 8 layers of point values is about 22,000–31,000 characters, and a page of 100 events about 16,000–24,000. A detailed answer holds about 40 values or events. One call also returns at most 500 rows in the concise format, 100 in the detailed format and 20,000 as CSV (places × layers × frames or samples; a magnetic layer is five rows), and a CSV download is at most 8,000,000 characters, measured on the CSV text. A call that would be larger is refused **before it runs**, free of charge, with `too_large` (reason `too_many_rows` or `response_size`) and a hint: fewer places or layers, a cursor for events, or `format=csv` on REST. Only a detailed caller is told to switch to the concise format. Nothing is cut off silently. ## Errors An error has the same outer shape, with `ok: false`. This is the recorded response to the same call with `lat=200`: ```json { "ok": false, "tool": "atlas_get_magnetic_field", "error": { "code": "invalid_input", "reason": "invalid_arguments", "message": "args.lat: must be at most 90.", "hint": "Check the arguments against this tool's inputSchema at /api/v1/agent/tools." } } ``` Errors that a different call can resolve also carry `next`, for example `{"tool": "atlas_layer_coverage", "args": {"layer": "pm25"}}`, and `busy`, `timeout` and `quota_exceeded` carry `retry_after` in seconds. `code` is the stable public vocabulary below. `reason` is the more specific internal cause, useful in bug reports. `hint` says what to change, and `next`, when present, is a call your agent can make to recover. Over MCP, a `tools/call` error is a tool result (HTTP 200) marked `isError: true`, with the same envelope in `structuredContent`, so your agent sees the `hint` and `retry_after`. That includes `too_large`, the daily and per-minute quotas (`quota_exceeded`, reason `quota_burst` for the per-minute limit), a lapsed plan (`plan_required`) and a suspended account (`suspended`). Other MCP methods, such as `tools/list`, answer those three account refusals with JSON-RPC error `-32000`, the envelope's `error` object in `data`, and HTTP 402, 403 or 429 with `Retry-After`. Over MCP, only these refusals are plain HTTP errors (`{"error": {...}}`, no JSON-RPC envelope): a missing or unknown key, or a key in the URL (HTTP 401 `invalid_key`), too many failed key attempts from one address (429 `quota_exceeded` with `retry_after` 600 and `Retry-After`), a request from a web page (403 `invalid_origin`) or to another host name (421 `invalid_host`), a method other than `POST` (405), a path other than `/mcp` (404) and a switched-off API (503 `disabled`). Everything else is JSON-RPC: the per-address limits (HTTP 429, error `-32000`, reason `ip_burst`), a body over 64 KiB (HTTP 413, error `-32000`, code `too_large`), a request without `application/json` in `Accept` (406) or as its body type (415), all with `id: null`, and malformed JSON (`-32700`), which includes a string that escapes an unpaired UTF-16 surrogate (HTTP 400, "Parse error: a string escapes an unpaired UTF-16 surrogate.", `id: null`). An unknown tool is `not_available` with reason `unknown_tool`: HTTP 404 on REST, JSON-RPC error `-32602` over MCP. Some `invalid_input` reasons worth knowing: `invalid_cursor` for a `find_events` cursor that this server did not write for the same search (repeat the search with the same arguments and the cursor it returned, or without a cursor); `invalid_text` on REST for a string argument or key with an unpaired UTF-16 surrogate, such as `"\ud83d"` from text cut in the middle of an emoji (whole characters and paired escapes are fine; over MCP the request is the `-32700` parse error above); and `control_character` for C0 or C1 control characters. None of them costs units. | Code | HTTP | Meaning | What to do | | ------------------ | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `invalid_key` | 401 | The key is missing, malformed, revoked, or not in the `Authorization` header. | Send `Authorization: Bearer `; create a new key if it was revoked. | | `invalid_input` | 400 | A parameter is missing, unknown or out of range. | Read `hint`; check the tool's schema at `/api/v1/agent/tools`. | | `invalid_place` | 400 | The place could not be found. | Try another spelling, add `place_country`, or call `atlas_find_place`. | | `ambiguous_place` | 409 | Several places match. | Choose one of the candidates and send its `place_id`. | | `no_coverage` | 404 | The layer has no value at that place or time (for example, sea temperature on land). | Call `atlas_layer_coverage`; pick another point or time. | | `not_retained` | 404 | That historical date is not held and cannot be loaded now, or the `snapshot_version` you sent is no longer kept. | Check the retained dates with `atlas_layer_coverage`, or use another layer; for a snapshot, use one the hint names or leave `snapshot_version` out. | | `outside_snapshot` | 404 | The time or window is outside the snapshot: past a forecast's last frame, outside a pinned `snapshot_version`, or an event window wholly outside the current snapshot (for example, earthquakes older than 30 days). | Narrow the dates to the snapshot that `atlas_layer_coverage` reports. | | `frame_too_far` | 404 | The newest data is too old to stand for `now`: a fire snapshot that ended more than 24 hours ago (also for today's date), a newest sea-temperature day more than 4 days old, or a forecast whose last frame is more than 3 hours before now. | Say the data is not current, or ask for an explicit time inside the snapshot. | | `not_available` | 404 | The atlas does not offer this, for example a multi-year environmental series. | Read `hint`; see [What the atlas does not answer](https://worldinlayers.com/developers.html#what-the-atlas-does-not-answer). | | `too_large` | 413 | The request or its answer is too big: more places than your plan's batch, a body over the size limit, or an answer over the limits. | Use fewer places or layers, a smaller area, or follow the cursor. | | `licence_pending` | 451 | The source's terms do not yet allow us to pass this on through the API. | Read `hint`; the website may still show it on the map. | | `plan_required` | 402 | The key's account has no active Plus or Pro subscription. `reason` says why: `no_subscription`, `lapsed`, `restricted` or `deleting`. | Renew at [/pricing](https://worldinlayers.com/pricing); the key works again once the plan is active. | | `scope_required` | 403 | Reserved: the key lacks the scope this tool needs (`read`, `cards` or `places`). Not returned today, because every key carries all three scopes. | — | | `suspended` | 403 | API access for this account is suspended. | Write to hello@worldinlayers.com. | | `quota_exceeded` | 429 | A daily, burst, cold-load, card or magnetic-map preparation quota is used up. The error names which. | Wait `retry_after` seconds, or until 00:00 UTC for daily quotas. | | `busy` | 503 | As many of your calls are running as your plan allows, the shared capacity or the archive loader is in use, an archive's provider did not answer, or a map card's magnetic field map is still being calculated. | Retry after `retry_after` seconds. | | `timeout` | 504 | The call ran past its 30-second budget. The charge stands, because the archive map it loaded is kept for your retry. | Retry the same call after `retry_after`. | | `disabled` | 503 | This tool, or the whole API, is switched off for maintenance. | Try later, or use another tool for the same data. | | `internal` | 500 | Something failed on our side. | Retry once; if it repeats, tell us at hello@worldinlayers.com with the time and `reason`. | ## Limits and headers - **Units per day, cold archive loads and map cards** reset at 00:00 UTC. - **Burst:** 120 requests a minute on Plus, 240 on Pro, per account. - **Concurrency:** 2 requests at the same time on Plus, 4 on Pro. One more is refused with `busy` (reason `account_concurrency`, `retry_after` 2) and costs nothing. A call counts until it has finished on our side, even if your client gave up, and is charged as usual. - **Batch size:** up to 10 places per call on Plus, 20 on Pro; more is refused with `too_large` (reason `batch_limit`). - **Time budget:** 30 seconds per call. - **Shared guards** protect the website for everyone, whatever your plan: at most 15 cold archive loads an hour across all keys, at most 32 a day (half of the 64-map history cache), of which one account may take at most 5 an hour and 16 a day; at most 6 API calls running at once across all keys; and at most 2 area-statistics calls at once, one per account. When one is reached you get `busy` or `quota_exceeded` with `retry_after`. - **Per address:** an address is an IPv4 address or an IPv6 /64 network. Requests to the tools and `/mcp` **without a valid key** are limited to 1,200 a minute per address; requests with a valid key answer to your account's burst instead, so other people's failed attempts behind a shared address, such as a hosted connector's, do not use up yours. A much higher safety ceiling (12,000 a minute) counts every request. Both answer `429 quota_exceeded` with reason `ip_burst` and a `retry_after` of 60 seconds. Failed authentication is limited to 30 attempts per 10 minutes per address; after that the address gets `429 quota_exceeded` with `retry_after` 600. - **Request size:** a REST body may be up to 256 KiB (262,144 bytes) and an MCP request up to 64 KiB (65,536 bytes); larger requests are refused with HTTP 413 `too_large` (reason `body_too_large`) before they run. Use `POST` for long arguments: a `GET` URL over about 16 KiB may be refused by the server with a plain HTTP 400 before the API sees it. Every keyed REST tool response for a known account carries these headers, refusals included: invalid arguments (also a body that is not a JSON object), the per-minute burst and a method the tool does not take (`405`). The key is checked before the arguments, so a missing or invalid key gets `401` whatever the arguments. Without a known account only `X-Atlas-Cost: 0` is sent, and the quota headers are left out rather than sent as 0: for `401`, the failed-key `429`, `402`, `403 suspended` and an unknown path, and for refusals made before the key is read (a wrong method, a body over the size limit or nested too deeply, the per-address limits, a switched-off API): | Header | Meaning | | ------------------------- | ------------------------------------ | | `X-Atlas-Units-Limit` | Your daily units. | | `X-Atlas-Units-Remaining` | Units left today. | | `X-Atlas-Units-Reset` | Seconds until 00:00 UTC. | | `X-Atlas-Cost` | Units this call cost. | | `X-Atlas-Burst-Limit` | Requests allowed per minute. | | `X-Atlas-Burst-Remaining` | Requests left in the current minute. | Responses are never cached (`Cache-Control: private, no-store`). There is no CORS: call the API from a server or an agent, not from a web page, so your key stays private. ## Attribution and citing The data comes from public agencies and research groups whose licences ask for credit. Those terms pass through to you: when you publish numbers from the atlas, show the credit for each provider involved. Each response already lists them in `attribution[]`; the full table is at [`/api/v1/agent/attribution`](https://worldinlayers.com/api/v1/agent/attribution). The copy-ready lines are below; the API fills in `[year]` with the current year. | Provider | Credit line (exactly as in `attribution[]`) | Licence | Also cite in research | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Copernicus ERA5 | Contains modified Copernicus Climate Change Service information [year]. Neither the European Commission nor ECMWF is responsible for any use that may be made of the Copernicus information or data it contains. | CC BY 4.0 | Hersbach, H. et al. (2023): ERA5 hourly data on single levels from 1940 to present. Copernicus Climate Change Service (C3S) Climate Data Store (CDS). DOI: 10.24381/cds.adbb2d47 | | CAMS EAC4 | Contains modified Copernicus Atmosphere Monitoring Service information [year]. Neither the European Commission nor ECMWF is responsible for any use that may be made of the Copernicus information or data it contains. | CC BY 4.0 | Inness, A. et al. (2019): The CAMS reanalysis of atmospheric composition. Atmospheric Chemistry and Physics, 19, 3515–3556. DOI: 10.5194/acp-19-3515-2019 | | FMI SILAM | Air-quality forecast: Finnish Meteorological Institute SILAM, CC BY 4.0. | CC BY 4.0 | — | | NOAA GFS | NOAA GFS: data from the US National Weather Service, public domain; attribution requested. | US government open data | — | | NOAA GFS-Wave | NOAA GFS-Wave: data from the US National Weather Service, public domain; attribution requested. | US government open data | — | | NOAA CPC UV | NOAA CPC UV index forecast: data from the US National Weather Service Climate Prediction Center, public domain; attribution requested. | US government open data | — | | NOAA NCEI OISST | NOAA OISST v2.1: NOAA National Centers for Environmental Information, public domain; attribution requested. | US government open data | Huang, B. et al. (2021): Improvements of the Daily Optimum Interpolation Sea Surface Temperature (DOISST) Version 2.1. Journal of Climate, 34, 2923–2939. DOI: 10.1175/JCLI-D-20-0166.1 | | NOAA PSL | NCEP/NCAR Reanalysis 1 data provided by the NOAA PSL, Boulder, Colorado, USA, from their website at https://psl.noaa.gov | US government open data | — | | NASA FIRMS | We acknowledge the use of data from NASA's Fire Information for Resource Management System (FIRMS) (https://www.earthdata.nasa.gov/firms), part of NASA's Earth Science Data and Information System (ESDIS). | NASA open data | — | | NASA Aura OMI | UV index: NASA Aura OMI OMUVBd v003, distributed by the NASA Goddard Earth Sciences Data and Information Services Center (GES DISC). | NASA open data | — | | USGS | Earthquakes: U.S. Geological Survey Earthquake Hazards Program and contributing seismic networks. | US public domain; retain contributing network credits | — | | NOAA NCEI volcanoes | Volcanoes: NOAA NCEI / WDS Global Significant Volcanic Eruptions Database; volcano locations compiled from the Smithsonian Global Volcanism Program. | CC0; retain attribution | NGDC/WDS, NOAA NCEI. doi:10.7289/V5JW8BSH | | GeoNames | Places: GeoNames (geonames.org), CC BY 4.0. Contains Royal Mail data © Royal Mail copyright and database right 2022. | CC BY 4.0 | — | | geoBoundaries | Administrative names: geoBoundaries (www.geoboundaries.org), CC BY 4.0. | CC BY 4.0 | Runfola, D. et al. (2020): geoBoundaries: A global database of political administrative boundaries. PLoS ONE 15(4), e0231866 | | GFZ | Geomagnetic indices: GFZ Helmholtz Centre for Geosciences, CC BY 4.0 (sunspot numbers are not included). | CC BY 4.0 | Matzka, J. et al. (2021): The geomagnetic Kp index and derived indices of geomagnetic activity. Space Weather, 19, e2020SW002641. DOI: 10.1029/2020SW002641 | | IGRF-14 | Magnetic field: IGRF-14, International Association of Geomagnetism and Aeronomy (IAGA); coefficients distributed by NOAA NCEI. | Public reference coefficients; attribution requested | — | | WMM | Magnetic field: World Magnetic Model WMM2025 / WMMHR2025, NOAA NCEI and the British Geological Survey; public domain. | US government open data | — | | CHAOS-8 | Magnetic field: CHAOS-8 model, Finlay and colleagues, DTU Space; published on Zenodo under CC BY 4.0. | CC BY 4.0 | — | | EMAG2 | Magnetic anomalies: EMAG2 v3, Meyer, Saltus & Chulliat (2017), NOAA NCEI; public domain. | US government open data | — | | EarthRef | Magnetic field: CALS10k.2 (Constable, Korte & Panovska 2016), GGF100k (Panovska, Constable & Korte 2018) and GGFMB (Mahgoub, Korte & Panovska 2023), EarthRef Digital Archive, CC BY 4.0. | CC BY 4.0 | — | | Natural Earth | Country outlines: Natural Earth, public domain. | Public domain | No credit required | | MLIT KSJ (Japan) | One line per dataset: 「国土数値情報(…)」(国土交通省)(page)を加工して作成, in English too, not endorsed by MLIT; exact lines at `/api/v1/agent/attribution` | CC BY 4.0 (KSJ terms); A22: 商用可 | Prefecture terms: `/api/v1/japan-hazards/status` | Do not use agency logos or suggest that a provider, NOAA included, endorses your work. If you change the data (convert units, average, crop), say so beside the credit. ### Citing a value To cite one number, give the provider, the data kind and valid time, the `snapshot_version` and the `source_url`. For example: > Temperature in Lisbon 19.2 °C, NOAA GFS forecast valid 23 October 2026 12:00 UTC, > World in Layers snapshot 20261023T051925-bc89e777, > https://worldinlayers.com/api/v1/environment/point?… The `source_url` returns the same value until `retained_until`. After that the snapshot is gone; keep the response if you need a permanent record. For area statistics and other derived figures, cite `reproduce` and the `method` text instead: calling `reproduce.tool` with `reproduce.args`, including its `snapshot_version`, recalculates the same figure from the same snapshot while it is retained. `atlas_get_point_values`, `atlas_get_time_series`, `atlas_area_stats` and `atlas_find_events` all accept `snapshot_version`, so the same values can be read again from a cited snapshot after a newer one is published. A badly formatted `snapshot_version` is `400 invalid_input`; a snapshot that is no longer kept answers `404 not_retained`, naming the range that is retained. When the newest snapshot has itself been current for more than 7 days, `retained_until` is left out: it is kept until the next one is published. Earthquake citations from the current snapshot also have no `retained_until`; a note says the snapshot is kept while it is current. A map card is a permanent, citable snapshot of its own. ## What the atlas does not answer - **No verdicts.** It never says whether something is safe, healthy or advisable, issues no warnings and gives no health, safety, travel or emergency advice. Where a question invites one, `notes[]` says the atlas shows data and points to national weather, marine or civil-protection services. Your agent should do the same. - **No scores** that combine layers, and no air-quality categories. - **No satellite pixel values.** The Sentinel layers (imagery, NDVI, NBR, SO₂, land surface temperature) are images on the website only. - **No Smithsonian GVP eruption records.** Volcano answers come from the NOAA significant-eruption catalogue, with links to GVP pages. - **No ESA Swarm measurements** and no geomagnetic observatory series. - **No boundary geometry.** geoBoundaries is used only to name the area around a point. - **No multi-year environmental series.** Series cover the current snapshot (forecast hours, recent sea-temperature days, the 12 climate months); magnetic series span centuries. For single historical dates, call `atlas_layer_coverage` first to see the archive range and retained dates. - **No imperial units, Parquet or GeoJSON**, and no named sub-national regions yet. - **No verdicts on Japanese hazard zones.** `atlas_japan_hazards` returns official designations and planning scenarios, never whether a place is fit to buy, rent or live in. Outside the mapped zones means only that the edition maps no zone there. It is not the municipal hazard map and cannot be used for the Important Matters Explanation (重要事項説明) in a property transaction; the official map is the Hazard Map Portal Site (重ねるハザードマップ), linked as `portal_url` for each place. ## Terms in plain words These points summarise how keys may be used; the [terms of service](https://worldinlayers.com/terms.html) govern. - **A key is personal.** Use it yourself and in your own agents, scripts and services. - **Do not embed a key in software you distribute** to other people, such as an app, a plugin or a public repository. Each person needs their own key. - **Quotas are part of the plan.** Do not spread one person's use across several accounts to get around them. - **Data licences flow through to you.** Show the attribution for what you publish and follow each provider's terms. - **What we record:** for each call, the time, your account, the key, REST or MCP, the tool, units, outcome, duration and the client name your software sends (up to 120 characters); calls refused before they run are recorded up to 100 per account a day. Kept for 90 days for quotas, abuse prevention and your usage page. We never record coordinates, place names or other content of your requests. See the [privacy policy](https://worldinlayers.com/privacy.html). - We may switch off a tool or the API for maintenance, and suspend API access or revoke a key that is abused, exposed or shared. ## Changelog **Last verified:** 24 October 2026, end to end against a local server of this release: keys, REST (JSON and CSV), MCP in both protocol eras, resources and prompts. ### Japan hazard zones - `atlas_japan_hazards`: official flood, tsunami, storm-surge, landslide and heavy-snow zones in Japan (MLIT National Land Numerical Information) and the projected population of the 1 km mesh, at up to 10 places (20 on Pro), 1 unit per place. New data kinds `official_designation` and `official_projection`; the seven Japan layers open with `atlas_map_link`. Also returns the J-SHIS 30-year probabilities of strong shaking for the 250 m mesh (`official_probability`) and the nearest official land prices (`official_price`, MLIT KSJ L01-2026) and the municipality's vacant-home rates (`official_statistics`, 2023 Housing and Land Survey). ### First release - REST tools at `/api/v1/agent/` and the MCP server at `/mcp`, with personal API keys for Plus and Pro members. - Twelve tools: `atlas_find_place`, `atlas_list_layers`, `atlas_layer_coverage`, `atlas_status`, `atlas_get_point_values`, `atlas_get_magnetic_field`, `atlas_get_time_series`, `atlas_find_events`, `atlas_area_stats`, `atlas_map_link`, `atlas_my_places` and `atlas_make_map_card`. - Weighted units, daily quotas, the response envelope with citations and attribution, the public error vocabulary and the `X-Atlas-*` headers. - MCP prompts `atlas_explain_place` and `atlas_compare_places`, and resources for the guide, layers and attribution.