{"openapi":"3.1.0","info":{"title":"USGS Earthquakes over Airnode","version":"1.0.0","description":"The USGS earthquake catalogue: every seismic event the Advanced National Seismic System has located, worldwide rather than American despite who runs it, from the last few minutes back through the historical record. This Airnode wraps its FDSN event service, so a consumer receives what the catalogue said at a moment with a signature saying this Airnode read it then.\n\nThat matters more here than it looks. An earthquake's magnitude and location are revised as more stations report: an event is first located automatically within minutes and reviewed by a seismologist afterwards, and the reviewed figure is often not the automatic one. So a response is what USGS believed at that time, the status field says which of the two it was, and asking again tomorrow is a legitimately different answer for the same event.\n\nThe format parameter is required rather than defaulted. The service answers QuakeML XML when nothing asks otherwise, and passing geojson is what produces the response this document describes.\n\nData source: U.S. Geological Survey Earthquake Hazards Program (https://earthquake.usgs.gov). USGS-produced data is in the public domain and may be reused commercially; USGS asks to be acknowledged, which this document does. USGS does not endorse, and is not affiliated with, API3, AirnodeHub or this Airnode.\n\nEvery response carries an EIP-191 signature from the Airnode that served it, so the data can be attributed back to its source rather than trusted on reputation."},"servers":[{"url":"https://airnode-usgs.fly.dev"}],"paths":{"/":{"get":{"operationId":"getDocumentation","summary":"This document.","description":"Describes the operations this Airnode serves and how to verify what it returns. Free.","responses":{"200":{"description":"An OpenAPI document describing this Airnode.","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"performRequest","summary":"Perform an operation and attest to the response.","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"title":"queryEvents","description":"Earthquakes matching a time, place, magnitude and depth.","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"queryEvents","description":"Every filter narrows, and they combine, so a search is written by adding them. A radius search wants latitude, longitude and maxradiuskm together; a box wants the four bounds; the two cannot be mixed. Unfiltered, this answers the last thirty days at every magnitude, which is megabytes, so a starttime or a minmagnitude is worth setting even when it does not matter.\n\nAsking for more than twenty thousand events is refused rather than truncated, which is what the count operation is for: it takes the same filters and answers only how many there are.\n\nThe response comes in two shapes and eventid is what decides which. A search answers a GeoJSON feature collection, one feature per event. Naming one event answers that feature on its own, unwrapped, and carrying a products field the search form leaves out: every seismic product attached to the event, which is tens of kilobytes and most of why the two are not the same call.","x-airnode-price":"0.01 USD per call","x-airnode-returns":{"type":"string","metadata":"object","bbox":"array","features":"array","id":"string","geometry":"object","properties":"object"}},"parameters":{"type":"object","additionalProperties":false,"required":["format"],"properties":{"format":{"description":"Pass geojson. The service defaults to QuakeML XML and ignores what a client says it accepts, so this is the only thing that produces the response described here. The others come back as the text they are rather than as anything this document promises.","type":"string","enum":["csv","geojson","kml","quakeml","text","xml"]},"eventid":{"description":"One event by its id, which is what an earlier response's id field carries. Everything else is ignored alongside it, and this is how an event is re-read later to see whether its magnitude was revised. It answers that one feature unwrapped rather than a collection, with a products field of tens of kilobytes the search leaves out.","type":"string","examples":["us6000tjl2"]},"starttime":{"description":"Events at or after this time, as YYYY-MM-DD or a full ISO 8601 timestamp in UTC. Omitted, thirty days ago. Thirty days at every magnitude is megabytes, so set this or minmagnitude.","type":"string"},"endtime":{"description":"Events at or before this time, same format. Omitted, now.","type":"string"},"updatedafter":{"description":"Only events whose record has changed since this time, same format. This is how revisions are found without re-reading the catalogue.","type":"string"},"minmagnitude":{"description":"Events at or above this magnitude. Around 4.5 is roughly what is felt, 6 is where damage starts.","type":"number"},"maxmagnitude":{"description":"Events at or below this magnitude.","type":"number"},"mindepth":{"description":"Events at or below this depth, in kilometres. Can be negative, since an event can be located above sea level.","type":"number"},"maxdepth":{"description":"Events at or above this depth, in kilometres.","type":"number"},"latitude":{"description":"Centre of a radius search, in degrees. Wants longitude and maxradiuskm with it.","type":"number","minimum":-90,"maximum":90},"longitude":{"description":"Centre of a radius search, in degrees.","type":"number","minimum":-180,"maximum":180},"maxradiuskm":{"description":"How far from that centre to search, in kilometres.","type":"number","minimum":0,"maximum":20001.6},"minlatitude":{"description":"Southern edge of a box search, in degrees. All four edges go together, and a box cannot be combined with a radius.","type":"number","minimum":-90,"maximum":90},"maxlatitude":{"description":"Northern edge of a box search, in degrees.","type":"number","minimum":-90,"maximum":90},"minlongitude":{"description":"Western edge of a box search, in degrees.","type":"number","minimum":-360,"maximum":360},"maxlongitude":{"description":"Eastern edge of a box search, in degrees.","type":"number","minimum":-360,"maximum":360},"alertlevel":{"description":"Only events USGS has given this PAGER alert level, which runs green to red in order of expected losses. A filter on this is the closest thing here to a search for events that mattered.","type":"string","enum":["green","yellow","orange","red"]},"eventtype":{"description":"Only events of this kind. The application operation lists them, and the catalogue is not only earthquakes.","type":"string","examples":["earthquake","quarry blast","explosion"]},"reviewstatus":{"description":"Which events to include. Reviewed means a seismologist has been over it, which is the figure worth relying on.","type":"string","enum":["automatic","reviewed","all"]},"catalog":{"description":"Only events from this contributing catalogue. The application operation lists them.","type":"string","examples":["us","ak"]},"limit":{"description":"How many events to return.","type":"integer","minimum":1,"maximum":20000},"offset":{"description":"Which matching event the page starts at, counting from 1, so the page after the first 20 starts at 21.","type":"integer","minimum":1,"default":1},"orderby":{"description":"Which order to answer in, by when or by how large. time leads with the newest.","type":"string","enum":["time","time-asc","magnitude","magnitude-asc"],"default":"time"}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string","pattern":"^/"},"maxProperties":20,"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data is then the text of a JSON object of those names in Unicode code point order, each value as the upstream wrote it, instead of the whole body, and the projection is part of the signed request identity. No two names take the same pointer, and no pointer is inside another's value. A pointer the response does not have is a 400."}}},{"title":"countEvents","description":"How many earthquakes a search would return.","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"countEvents","description":"The same filters as the query operation, answering only the number. Worth calling first, since a search matching more than the maximum is refused rather than truncated, and this is how a caller finds that out for the price of a few bytes rather than by fetching megabytes.","x-airnode-returns":{"count":"integer","maxAllowed":"integer"}},"parameters":{"type":"object","additionalProperties":false,"required":["format"],"properties":{"format":{"description":"Pass geojson. Without it this answers a bare number as plain text rather than the object described here.","type":"string","enum":["geojson","text","xml"]},"starttime":{"description":"Events at or after this time, as YYYY-MM-DD or a full ISO 8601 timestamp in UTC. Omitted, thirty days ago.","type":"string"},"endtime":{"description":"Events at or before this time, same format.","type":"string"},"minmagnitude":{"description":"Events at or above this magnitude.","type":"number"},"maxmagnitude":{"description":"Events at or below this magnitude.","type":"number"},"latitude":{"description":"Centre of a radius search, in degrees.","type":"number","minimum":-90,"maximum":90},"longitude":{"description":"Centre of a radius search, in degrees.","type":"number","minimum":-180,"maximum":180},"maxradiuskm":{"description":"How far from that centre to search, in kilometres.","type":"number","minimum":0,"maximum":20001.6},"minlatitude":{"description":"Southern edge of a box search, in degrees.","type":"number","minimum":-90,"maximum":90},"maxlatitude":{"description":"Northern edge of a box search, in degrees.","type":"number","minimum":-90,"maximum":90},"minlongitude":{"description":"Western edge of a box search, in degrees.","type":"number","minimum":-360,"maximum":360},"maxlongitude":{"description":"Eastern edge of a box search, in degrees.","type":"number","minimum":-360,"maximum":360},"alertlevel":{"description":"Only events at this PAGER alert level, which runs green to red in order of expected losses.","type":"string","enum":["green","yellow","orange","red"]},"eventtype":{"description":"Only events of this kind.","type":"string","examples":["earthquake"]}}},"responseProjection":{"type":"object","additionalProperties":{"type":"string","pattern":"^/"},"maxProperties":20,"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data is then the text of a JSON object of those names in Unicode code point order, each value as the upstream wrote it, instead of the whole body, and the projection is part of the signed request identity. No two names take the same pointer, and no pointer is inside another's value. A pointer the response does not have is a 400."}}},{"title":"getApplication","description":"The vocabularies the filters are written in.","type":"object","required":["operation","parameters"],"additionalProperties":false,"properties":{"operation":{"const":"getApplication","description":"The contributing catalogues, the agencies contributing to them, the kinds of event the catalogue holds, the magnitude scales in use and the products attached to an event. This is where the values of catalog and eventtype come from, and it is the one operation here that needs no format parameter, because it only ever answers JSON.","x-airnode-returns":{"catalogs":"array","contributors":"array","producttypes":"array","eventtypes":"array","magnitudetypes":"array"}},"parameters":{"type":"object","additionalProperties":false,"required":[],"properties":{}},"responseProjection":{"type":"object","additionalProperties":{"type":"string","pattern":"^/"},"maxProperties":20,"description":"Optional. Maps a name of your choosing to an RFC 6901 JSON Pointer into the upstream response, such as {\"price\": \"/ethereum/usd\"}. data is then the text of a JSON object of those names in Unicode code point order, each value as the upstream wrote it, instead of the whole body, and the projection is part of the signed request identity. No two names take the same pointer, and no pointer is inside another's value. A pointer the response does not have is a 400."}}}]}}}},"responses":{"200":{"description":"The upstream response and the attestation over it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Attestation"}}}},"400":{"description":"The operation exists but the parameters or the projection are missing, unknown or malformed, a path parameter is empty, . or .. or has such a part between slashes, or the projection names too many fields, an empty or repeated pointer, or a path the response does not have. Also a PAYMENT-SIGNATURE header that does not decode to a payment payload."},"402":{"description":"The operation is paid and no valid payment was supplied. The PAYMENT-REQUIRED header carries the x402 payment requirements to retry against."},"404":{"description":"No such operation."},"502":{"description":"The upstream API could not be reached or refused the request."}}}}},"components":{"schemas":{"Attestation":{"type":"object","required":["airnode","requestHash","timestamp","data","signature"],"properties":{"airnode":{"type":"string","description":"The address whose signature attests to this response."},"requestHash":{"type":"string","description":"Identifies the request this response answers."},"timestamp":{"type":"string","description":"Unix seconds at which the response was signed."},"data":{"type":"string","description":"The upstream response body exactly as received, less a leading byte order mark. With a projection, the text of a JSON object keyed by the names it asked for in Unicode code point order, each value as the upstream wrote it."},"signature":{"type":"string","description":"The attestation itself."}}}}},"x-airnode":{"address":"0x5aF744115e2577513D878D4263Db73b3E77E7630","version":"0.2.0","attestation":{"scheme":"eip191-secp256k1","digest":"keccak256(abi.encodePacked(bytes32 requestHash, uint256 timestamp, bytes dataBytes))","dataBytes":"UTF-8 of data","requestHash":"keccak256(utf8(JSON.stringify([operation, parameterEntriesSortedByName]))), where an object value is itself entries sorted by name, at any depth, and an array keeps its order. Names are compared by Unicode code point. A request that carries a projection appends its entries, sorted the same way, as a third element","verify":"Recover the signer of the signature over the digest and check it equals the address above."},"passthrough":{"url":"https://airnode-usgs.fly.dev/api","routes":{"queryEvents":{"method":"GET","path":"/query","parameters":{"format":"query","eventid":"query","starttime":"query","endtime":"query","updatedafter":"query","minmagnitude":"query","maxmagnitude":"query","mindepth":"query","maxdepth":"query","latitude":"query","longitude":"query","maxradiuskm":"query","minlatitude":"query","maxlatitude":"query","minlongitude":"query","maxlongitude":"query","alertlevel":"query","eventtype":"query","reviewstatus":"query","catalog":"query","limit":"query","offset":"query","orderby":"query"}},"countEvents":{"method":"GET","path":"/count","parameters":{"format":"query","starttime":"query","endtime":"query","minmagnitude":"query","maxmagnitude":"query","latitude":"query","longitude":"query","maxradiuskm":"query","minlatitude":"query","maxlatitude":"query","minlongitude":"query","maxlongitude":"query","alertlevel":"query","eventtype":"query"}},"getApplication":{"method":"GET","path":"/application.json","parameters":{}}},"parameters":{"x-airnode-sign":"false skips the signature: no attestation headers, and the body streamed through with no size cap.","x-airnode-project":"alias:pointer, once per field to keep and at most 20 times, each pointer an RFC 6901 JSON Pointer into the upstream response that starts with /, is not repeated and is not inside another's value. The body becomes an object of those aliases in Unicode code point order, the signature covers it, and a pointer the response does not have is a 400."},"flow":"Send the request the provider documents, method, path, query and body as they are, to url followed by the route's path. The body comes back as the upstream sent it, with the upstream's status, and on success the attestation is in the X-Airnode-Address, X-Airnode-Request-Hash, X-Airnode-Timestamp and X-Airnode-Signature headers, with the operation served in X-Airnode-Operation. Every query parameter starting with x-airnode- is this Airnode's own, listed under parameters, and never reaches the upstream.","requestHash":"keccak256(utf8(JSON.stringify([\"passthrough\", method, path, queryEntries, headerEntries, body]))), where method is upper case, path is what was sent after url as a URL parser resolves it, the query entries are what was sent with the Airnode's own parameters removed, in the order sent, headerEntries are the headers that the routes declare as parameters and the request sent, each name in lower case and sorted by Unicode code point, with the values of a header sent more than once joined with \", \" in the order sent and the result trimmed of spaces and tabs, and body is the request body as sent, or an empty string. A request that carries a projection appends its entries, sorted by name in Unicode code point order, as a seventh element","dataBytes":"UTF-8 of the response body exactly as received, less a leading byte order mark, or of the projected object"},"payment":{"x402Version":2,"scheme":"exact","accepts":[{"network":"eip155:84532","asset":"0xbeA34973e5f67F18F656A2C6070C64326C791808","symbol":"aUSD","decimals":6}],"payTo":"0x1505FD562AC2Fb4307B85BC6c672FfeafB4d57A7","facilitator":"https://facilitator.payai.network","prices":{"queryEvents":"0.01"},"flow":"An unpaid call to a priced operation returns 402 with the x402 payment requirements, base64-encoded, in the PAYMENT-REQUIRED header. Sign an EIP-3009 authorization matching one entry and retry the call with the payment payload, base64-encoded, in the PAYMENT-SIGNATURE header. The settlement receipt comes back in the PAYMENT-RESPONSE header."}}}