{"openapi":"3.0.3","info":{"title":"Onokoro API","version":"1.0.0","description":"High-precision elevation, terrain, and volcano-monitoring data for the\nJapanese archipelago. Backed by the Japan Geospatial Information Authority\n(国土地理院 / GSI) 5 m and 10 m digital elevation models.\n\nUse this API to:\n- Look up elevation for any (lat, lon) inside Japan.\n- Profile elevation along a route or grid.\n- Trace line-of-sight or signal-propagation rays.\n- Track 23 active Japanese volcanoes for elevation changes that signal\n  uplift, deflation, or eruption activity.\n\nCoverage is **Japanese territory only**. Queries outside Japan return 404\nor 0 m. Data refresh: GSI publishes DEM updates monthly; volcano elevation\nsnapshots are checked daily.\n","contact":{"name":"Onokoro Support","email":"support@onokoro.org"},"license":{"name":"MIT License","url":"https://opensource.org/licenses/MIT"}},"servers":[{"url":"https://api.onokoro.org","description":"Production server"},{"url":"http://localhost:8787","description":"Local development"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"paths":{"/":{"get":{"summary":"API root information","operationId":"getRoot","tags":["System"],"security":[],"responses":{"200":{"description":"API information","content":{"application/json":{"schema":{"type":"object","properties":{"service":{"type":"string","example":"onokoro"},"version":{"type":"string","example":"1.0.0"},"description":{"type":"string"},"endpoints":{"type":"array","items":{"type":"string"}}}}}}}}}},"/health":{"get":{"summary":"Health check","operationId":"healthCheck","tags":["System"],"security":[],"responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/elevation":{"get":{"summary":"Get elevation in meters for one (lat, lon) point in Japan.","description":"Returns elevation in meters for a single coordinate pair, using the\nGSI 5 m DEM where available (urban areas, mainland Honshu coasts) and\nfalling back to 10 m DEM elsewhere. Cached at the edge with regional\nTTL.\n\nCoverage: Japanese territory only — queries outside Japan return 0 m\nwith `source: \"outside_coverage\"`. Ocean returns 0 m.\n\nFor more than ~10 points in one call, prefer `getBatchElevation`.\n","operationId":"getElevation","tags":["Elevation"],"security":[],"parameters":[{"name":"lat","in":"query","required":true,"description":"Latitude in decimal degrees, WGS84.","example":35.6812,"schema":{"type":"number","format":"double","minimum":-90,"maximum":90}},{"name":"lon","in":"query","required":true,"description":"Longitude in decimal degrees, WGS84.","example":139.7671,"schema":{"type":"number","format":"double","minimum":-180,"maximum":180}}],"responses":{"200":{"description":"Elevation data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ElevationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/api/v1/elevation/batch":{"post":{"summary":"Get elevation for up to 500 points in one request.","description":"Batch elevation lookup. Submit up to 500 (lat, lon) points and receive\nelevation values in the same order. Per-request rate limited rather\nthan per-point, so this is far cheaper than 500 single calls.\n\nRequires an API key with the `batch_requests` feature (Starter plan or\nabove). Use this for terrain profiles, route surveys, and bulk grid\nsampling.\n","operationId":"getBatchElevation","tags":["Elevation"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["points"],"properties":{"points":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["lat","lon"],"properties":{"lat":{"type":"number","format":"double","minimum":-90,"maximum":90},"lon":{"type":"number","format":"double","minimum":-180,"maximum":180}}}}}},"example":{"points":[{"lat":35.6812,"lon":139.7671},{"lat":34.6937,"lon":135.5023}]}}}},"responses":{"200":{"description":"Batch elevation data","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ElevationData"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/api/v1/elevation/grid":{"get":{"summary":"Sample elevation on a regular lat/lon grid.","description":"Returns elevations on a regular grid defined by a bounding box and\nstep size. Useful for heatmaps, contour generation, and surface\nmodelling at moderate resolution.\n\nRequires API key with the `advanced_terrain` feature (Professional\nplan). For more than ~5,000 points the grid is capped — use the POST\nvariant with `maxPoints` to control behaviour.\n","operationId":"getElevationGrid","tags":["Elevation"],"parameters":[{"name":"minLat","in":"query","required":true,"description":"Southern edge of the bounding box (degrees).","example":35.65,"schema":{"type":"number","format":"double"}},{"name":"maxLat","in":"query","required":true,"description":"Northern edge of the bounding box (degrees).","example":35.7,"schema":{"type":"number","format":"double"}},{"name":"minLon","in":"query","required":true,"description":"Western edge of the bounding box (degrees).","example":139.74,"schema":{"type":"number","format":"double"}},{"name":"maxLon","in":"query","required":true,"description":"Eastern edge of the bounding box (degrees).","example":139.78,"schema":{"type":"number","format":"double"}},{"name":"step","in":"query","required":false,"description":"Grid step size in degrees. Default 0.001 (~100 m).","example":0.001,"schema":{"type":"number","format":"double","default":0.001}}],"responses":{"200":{"description":"Grid elevation data"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Sample elevation on a custom grid (POST variant).","description":"POST variant of `getElevationGrid` for clients that need to send\ncomplex grid descriptors (rotation, irregular spacing, masking) that\nwon't fit cleanly in query string. Same auth and feature requirement.\n","operationId":"postElevationGrid","tags":["Elevation"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bbox"],"properties":{"bbox":{"type":"object","description":"Bounding box [minLat, minLon, maxLat, maxLon]."},"step":{"type":"number","default":0.001},"maxPoints":{"type":"integer","default":5000}}}}}},"responses":{"200":{"description":"Grid elevation data"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/v1/elevation/profile":{"post":{"summary":"Profile elevation along a polyline (route, river, etc.).","description":"Walks a polyline and samples elevation at every step along the path,\nreturning the cumulative distance + elevation series for plotting\nterrain profiles.\n\nUse this for hiking-route altitude charts, river slope analysis, road\ngradient surveys. Requires API key with the `advanced_terrain` feature.\n","operationId":"getElevationProfile","tags":["Elevation"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["points"],"properties":{"points":{"type":"array","description":"Polyline waypoints in order.","minItems":2,"items":{"type":"object","required":["lat","lon"],"properties":{"lat":{"type":"number"},"lon":{"type":"number"}}}},"stepSize":{"type":"number","default":10,"description":"Sampling step in metres along the polyline."}}}}}},"responses":{"200":{"description":"Profile elevation series"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/v1/elevation/ray-path":{"post":{"summary":"Trace a ray for line-of-sight or signal-propagation analysis.","description":"Fires a ray from an origin point at the given azimuth and altitude\nangle, and returns the path profile annotated with the first terrain\nintersection (if any). Used for radio LOS, microwave link planning,\nsolar shadow casting, and viewshed analysis.\n\nOrigin `height` is metres above mean sea level (the ray's start\naltitude is `terrain_elevation_at_origin + height`). Returns\n`intersected: false` if the ray clears all terrain within `maxDistance`.\n","operationId":"getRayPath","tags":["Elevation"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["origin","azimuth","altitude"],"properties":{"origin":{"type":"object","required":["lat","lon","height"],"properties":{"lat":{"type":"number"},"lon":{"type":"number"},"height":{"type":"number","description":"Antenna/observer height in metres."}}},"azimuth":{"type":"number","minimum":0,"maximum":360,"description":"Compass bearing of the ray (0 = north, 90 = east)."},"altitude":{"type":"number","minimum":-90,"maximum":90,"description":"Vertical angle of the ray (0 = horizontal, 90 = up)."},"maxDistance":{"type":"number","default":5000,"description":"Maximum trace distance in metres."},"stepSize":{"type":"number","default":10,"description":"Sample step in metres along the ray."}}}}}},"responses":{"200":{"description":"Ray path trace results"},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/api/v1/legacy/elevation":{"get":{"summary":"Legacy elevation endpoint — prefer `/api/v1/elevation`.","description":"Backwards-compatible alias for the original elevation route. Kept for\nclients that integrated against the pre-1.0 API. New integrations\nshould call `getElevation` instead — the modern endpoint has identical\ncoverage but cleaner response schema and better caching.\n","operationId":"getLegacyElevation","tags":["Elevation"],"security":[],"deprecated":true,"parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","format":"double"}},{"name":"lon","in":"query","required":true,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Elevation data (legacy schema)"}}}},"/api/account":{"get":{"summary":"Get the authenticated caller's account, plan, and usage.","description":"Returns the API key holder's account info: email, plan tier, monthly\nrequest quota and current usage, enabled feature flags, and\nsubscription status. Use this to display dashboards and to gate\nclient-side feature toggles.\n","operationId":"getAccount","tags":["Account"],"responses":{"200":{"description":"Account information"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/metadata/enums":{"get":{"summary":"List every enum used by the Onokoro API (with localised labels).","description":"Returns the full set of enums (DEM source, plan tier, volcano alert\nlevels, etc.) with localised labels in the caller's language\n(`Accept-Language` header). Useful when building UIs that need to\nrender dropdowns matching the API's own vocabulary.\n","operationId":"listEnums","tags":["Metadata"],"security":[],"responses":{"200":{"description":"Enum metadata"}}}},"/v1/metadata/enums/{name}":{"get":{"summary":"Get a single enum by name.","description":"Returns localised values for one enum. See `listEnums` for the full\ndirectory of available enum names.\n","operationId":"getEnum","tags":["Metadata"],"security":[],"parameters":[{"name":"name","in":"path","required":true,"description":"The enum's identifier (e.g. `dem_source`, `volcano_alert_level`).","example":"dem_source","schema":{"type":"string"}}],"responses":{"200":{"description":"Enum values"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/monitoring/locations":{"get":{"summary":"List the caller's tracked elevation-monitoring locations.","description":"Returns all custom monitoring locations the API key owner has\nregistered, with their last-checked elevation and any detected\nchange since the previous snapshot.\n\nPair with `getElevationHistory` to chart per-location time series.\n","operationId":"listMonitoringLocations","tags":["Monitoring"],"security":[],"responses":{"200":{"description":"List of monitoring locations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/MonitoringLocation"}}}}}}}}},"post":{"summary":"Register a new elevation-monitoring location.","description":"Adds a (lat, lon) point to the caller's monitoring list. Onokoro will\nrecord its elevation snapshot daily and surface deltas via\n`listMonitoringChanges`. Plan limits apply on the number of locations.\n","operationId":"addMonitoringLocation","tags":["Monitoring"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","lat","lon"],"properties":{"name":{"type":"string","description":"Caller-chosen identifier (used in DELETE / history calls).","example":"meiji-jingu"},"lat":{"type":"number"},"lon":{"type":"number"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Location added successfully"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/monitoring/locations/{id}":{"delete":{"summary":"Stop monitoring a location.","operationId":"deleteMonitoringLocation","description":"Removes the location from the caller's monitoring list. Historical\nelevation snapshots for this location are preserved for 90 days and\nthen purged.\n","tags":["Monitoring"],"parameters":[{"name":"id","in":"path","required":true,"description":"The location identifier supplied at creation time.","example":"meiji-jingu","schema":{"type":"string"}}],"responses":{"200":{"description":"Location deleted successfully"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/monitoring/history/{id}":{"get":{"summary":"Get the elevation time series for a tracked location.","description":"Returns the elevation snapshot history (typically daily) for a single\nlocation, including a `change` field measuring delta-from-previous in\nmetres. Useful for trend charts and uplift/subsidence analysis.\n","operationId":"getElevationHistory","tags":["Monitoring"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"Location identifier (as registered via `addMonitoringLocation`).","example":"meiji-jingu","schema":{"type":"string"}}],"responses":{"200":{"description":"Elevation history"}}}},"/monitoring/volcanoes":{"get":{"summary":"List the 23 actively-monitored Japanese volcanoes.","description":"Returns Onokoro's curated list of the 23 most active Japanese\nvolcanoes (Sakurajima, Aso, Kirishima, etc.), each with current\nelevation, JMA alert level, and the timestamp of the most recent\nelevation check.\n\nUse the `getVolcanoElevationHistory` endpoint for time series, and\n`listLiveVolcanoActivity` for current-status feeds.\n","operationId":"listVolcanoes","tags":["Volcanoes"],"security":[],"responses":{"200":{"description":"List of monitored volcanoes"}}}},"/monitoring/volcanoes/live":{"get":{"summary":"Live activity status for monitored volcanoes (JMA + GSI).","description":"Aggregates the latest JMA alert levels and GSI elevation deltas across\nthe 23 monitored volcanoes, returning a snapshot of \"what's happening\nnow\" — eruption, swelling, normal — as a single feed.\n","operationId":"listLiveVolcanoActivity","tags":["Volcanoes"],"security":[],"responses":{"200":{"description":"Live volcano activity"}}}},"/monitoring/volcanoes/priority-watch":{"get":{"summary":"List volcanoes the caller has flagged for priority watch.","description":"Returns the user-curated subset of volcanoes elevated to \"priority\nwatch\" — daily refresh, change-detection alerts, and webhook\nnotifications. Per-account list, requires API key.\n","operationId":"listPriorityWatchVolcanoes","tags":["Volcanoes"],"security":[],"responses":{"200":{"description":"Priority-watch volcanoes"}}},"post":{"summary":"Add a volcano to priority watch.","description":"Promotes a volcano (by name) into the caller's priority-watch list.\nTrigger this when an LLM agent decides to follow a volcano based on\nrecent activity from `listLiveVolcanoActivity`.\n","operationId":"addPriorityWatchVolcano","tags":["Volcanoes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Volcano name (use the `name` field from `listVolcanoes`).","example":"sakurajima"}}}}}},"responses":{"200":{"description":"Added to priority watch"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/monitoring/volcanoes/priority-watch/{name}":{"delete":{"summary":"Remove a volcano from priority watch.","operationId":"removePriorityWatchVolcano","tags":["Volcanoes"],"parameters":[{"name":"name","in":"path","required":true,"description":"Volcano name as listed in `listVolcanoes`.","example":"sakurajima","schema":{"type":"string"}}],"responses":{"200":{"description":"Removed from priority watch"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/monitoring/volcanoes/history/{name}":{"get":{"summary":"Get long-term elevation history for one volcano.","description":"Returns daily elevation snapshots for a single volcano (typically\n365+ days), suitable for trend lines, uplift detection, and\ncorrelating with JMA alert level changes.\n","operationId":"getVolcanoElevationHistory","tags":["Volcanoes"],"security":[],"parameters":[{"name":"name","in":"path","required":true,"description":"Volcano name (lowercase, hyphenated; see `listVolcanoes`).","example":"sakurajima","schema":{"type":"string"}}],"responses":{"200":{"description":"Volcano elevation history"}}}},"/monitoring/changes":{"get":{"summary":"List recent elevation changes across all tracked locations.","description":"Returns the most recent elevation deltas (uplift or subsidence)\ndetected in the caller's monitoring list and the curated volcanoes,\nsorted by magnitude. Use this as the daily \"what changed?\" feed for\nagents and dashboards.\n","operationId":"listMonitoringChanges","tags":["Monitoring"],"security":[],"parameters":[{"name":"minDelta","in":"query","required":false,"description":"Only return changes with absolute delta ≥ this value (metres).","example":0.05,"schema":{"type":"number","default":0}},{"name":"limit","in":"query","required":false,"description":"Maximum number of entries to return.","example":50,"schema":{"type":"integer","default":100,"maximum":500}}],"responses":{"200":{"description":"Recent elevation changes"}}}},"/api/admin/security-audit/history":{"get":{"summary":"Read the per-account security-audit log.","description":"Returns the recent security-audit events recorded for the caller's\naccount: failed-auth bursts, unusual IP/UA patterns, rate-limit\nbreaches. Admin endpoint — requires elevated API key.\n","operationId":"getSecurityAuditHistory","tags":["Admin"],"responses":{"200":{"description":"Security-audit history"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/admin/security-audit/run":{"post":{"summary":"Manually trigger a security-audit pass.","description":"Forces an immediate audit pass on the caller's account, returning a\nreport identical to the daily scheduled audit. Use after rotating an\nAPI key or investigating suspicious activity.\n","operationId":"runSecurityAudit","tags":["Admin"],"responses":{"200":{"description":"Security-audit report"},"401":{"$ref":"#/components/responses/Unauthorized"}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key sent via header (X-API-Key). Obtain from the PPN Hub developer portal."},"BearerAuth":{"type":"http","scheme":"bearer","description":"Bearer token (JWT) for authenticated requests. Obtain by authenticating via the auth endpoint."}},"schemas":{"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy"]},"service":{"type":"string"},"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"ElevationData":{"type":"object","properties":{"lat":{"type":"number","format":"double"},"lon":{"type":"number","format":"double"},"elevation":{"type":"number","format":"double","description":"Elevation in meters"},"resolution":{"type":"string","enum":["5m","10m"]},"source":{"type":"string","example":"GSI"},"cached":{"type":"boolean"},"timestamp":{"type":"string","format":"date-time"}}},"ElevationResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ElevationData"}}},"MonitoringLocation":{"type":"object","properties":{"name":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"description":{"type":"string"},"elevation":{"type":"number"},"last_checked":{"type":"string","format":"date-time"},"change_detected":{"type":"boolean"}}},"PricingPlan":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"price_monthly":{"type":"number"},"requests_per_month":{"type":"integer"},"batch_size_max":{"type":"integer"},"monitoring_locations":{"type":"integer"},"features":{"type":"array","items":{"type":"string"}}}},"ErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean","example":false},"error":{"type":"string"},"message":{"type":"string"},"details":{"type":"object"}}}},"responses":{"BadRequest":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Unauthorized - Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimitExceeded":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"tags":[{"name":"System","description":"Health, version, and root metadata endpoints. Excluded from MCP tool surface."},{"name":"Elevation","description":"Single-point and bulk elevation, terrain profiles, and ray-path tracing."},{"name":"Monitoring","description":"User-defined locations being watched for elevation change."},{"name":"Volcanoes","description":"23 actively-monitored Japanese volcanoes with elevation and JMA alert tracking."},{"name":"Account","description":"Caller account, plan, and usage info."},{"name":"Metadata","description":"Localised enum lookups for client-side UIs."},{"name":"Admin","description":"Per-account security-audit operations (elevated API key)."}]}