Get a free API key

This page as Markdown, byte for byte: /events.md

Events: the hazard record behind a result#

A backtest tells you six years paid and names the events it paid on. This page is where those names come apart into the record itself: the catalogue Craton read, the exact solutions that qualified, and the rule that collapsed several of them into one occurrence.

Two routes, both reads, neither metered:

Route What it answers
GET /events/{peril} The pinned event catalogue for a peril, filtered the way a structure filters it
GET /events/{peril}/{event_id}/footprint One event's footprint as the record has it: the occurrence it belongs to, and the box that occurrence spans

Read the quickstart first for the two values you export (CEDE_BASE_URL, CEDE_API_KEY) and how to get a key from POST /signup. Feeds is the neighbouring page: it serves the publisher's bytes verbatim so you can check the digest, and this page serves the same bytes parsed the way the engine parses them.

What is served, and what is not#

Event catalogues are served for perils this build pins a catalogue of. Today that is **earthquake**, from the USGS Kanto extract. A peril whose pinned record is a gridded daily series — rainfall, wind — has no event catalogue here, and asking for one is answered with a 404 no_event_catalogue rather than with events manufactured out of exceedance days:

{ "error": {
    "status": 404,
    "code": "no_event_catalogue",
    "message": "this build pins no event catalogue for peril 'tropical_cyclone'. Event catalogues are served for earthquake. …" } }

The refusal names the perils that do answer, so finding the right one costs a round trip rather than a search.

A footprint here is a cluster of catalogue solutions, not a shaking map. The pinned snapshot holds hypocentres, depths and magnitudes — it holds no modelled intensity surface, so none is published. Synthesising one would be a model, with assumptions and a version and a card on it, and a model belongs in the registry rather than behind a data route. Every footprint response says this in its own limitations.


Reading the catalogue#

set -euo pipefail

: "${CEDE_BASE_URL:?export CEDE_BASE_URL first — see the quickstart}"
: "${CEDE_API_KEY:?export CEDE_API_KEY first — see the quickstart}"

# 1 — The first page of the pinned earthquake catalogue.
curl -sS "$CEDE_BASE_URL/events/earthquake?limit=5" \
  -H "Authorization: Bearer $CEDE_API_KEY" > events.json

python3 -c 'import json
page = json.load(open("events.json"))
feed = page["feed"]
print("catalogue:", feed["id"], "vintage", feed["vintage"])
print("digest:   ", feed["sha256"])
print("in snapshot:", page["counts"]["events_in_snapshot"],
      "selected:", page["counts"]["selected"],
      "on this page:", page["counts"]["returned"])
for event in page["events"]:
    print("  ", event["time"], "M" + str(event["magnitude"]),
          event["latitude"], event["longitude"],
          "depth", event["depth_km"], "km", "—", event["event_id"])'

# 2 — The same catalogue, filtered the way a structure filters it: a magnitude
#     floor, a box and a period. The response states the filter back.
curl -sS "$CEDE_BASE_URL/events/earthquake?min_magnitude=6.5&min_lat=34&max_lat=37&min_lon=138&max_lon=141.5&from=1986-01-01&to=2026-01-01&limit=50" \
  -H "Authorization: Bearer $CEDE_API_KEY" > qualifying.json

python3 -c 'import json
page = json.load(open("qualifying.json"))
selection = page["selection"]
print("M>=", selection["minimum_magnitude"],
      "in", selection["box"]["min_latitude"], "-", selection["box"]["max_latitude"], "N",
      selection["box"]["min_longitude"], "-", selection["box"]["max_longitude"], "E")
print("from", selection["from"], "to", selection["to"], "(", selection["period_bounds"], ")")
print("defaulted:", selection["defaulted"] or "nothing — every filter was yours")
print(page["counts"]["selected"], "events qualify")
print("next page:", page["page"]["next"])'

# 3 — The digest on the response is the digest of the pinned file, so the
#     events above and the bytes GET /feeds serves are one snapshot.
FEED_ID="$(python3 -c 'import json; print(json.load(open("events.json"))["feed"]["id"])')"
VERSION="$(python3 -c 'import json; print(json.load(open("events.json"))["feed"]["version"])')"

curl -sS "$CEDE_BASE_URL/feeds/$FEED_ID/versions/$VERSION" \
  -H "Authorization: Bearer $CEDE_API_KEY" > manifest.json

python3 -c 'import json
served = json.load(open("events.json"))["feed"]["sha256"]
pinned = json.load(open("manifest.json"))["sha256"]
print("same snapshot:", served == pinned)'

The parameters#

Parameter Default What it does
feed, version the latest pinned vintage Pin the exact snapshot. A result names both in its assumption set; pass them to read the record that result read.
min_magnitude the snapshot's own minimum Magnitude floor. Never below the snapshot's minimum: the events under it are missing from the extract, not from history.
max_depth_km none Focal depth limit. An event with no published depth is excluded when a limit is set, never assumed shallow.
from, to the snapshot's period of record from inclusive, to exclusive, so consecutive periods tile without counting a midnight event twice. A bare date is midnight UTC.
min_lat, max_lat, min_lon, max_lon the snapshot's own box An axis-aligned box, inclusive on every edge. All four or none — three edges describe no region.
limit, offset 100, 0 Paging. The ceiling is 1000; follow page.next, which pins the feed and version so a walk cannot mix two vintages.

Anything else is refused with 422 invalid_request rather than ignored: a parameter answered as though it were another would hand you a different set of events with no way to tell.


Reading one event's footprint#

set -euo pipefail

: "${CEDE_BASE_URL:?export CEDE_BASE_URL first — see the quickstart}"
: "${CEDE_API_KEY:?export CEDE_API_KEY first — see the quickstart}"

# 1 — Find a large event. Every event carries the address of its own footprint.
curl -sS "$CEDE_BASE_URL/events/earthquake?min_magnitude=7.0&limit=1" \
  -H "Authorization: Bearer $CEDE_API_KEY" > big.json

FOOTPRINT="$(python3 -c 'import json
page = json.load(open("big.json"))
assert page["events"], "no M7.0+ event in this catalogue"
print(page["events"][0]["footprint"])')"
echo "reading $FOOTPRINT"

# 2 — The footprint: the occurrence this event belongs to.
curl -sS "$CEDE_BASE_URL$FOOTPRINT" \
  -H "Authorization: Bearer $CEDE_API_KEY" > footprint.json

python3 -c 'import json
document = json.load(open("footprint.json"))
occurrence = document["footprint"]["occurrence"]
extent = document["footprint"]["extent"]
print("event:     ", document["event_id"], "M" + str(document["event"]["magnitude"]))
print("catalogue: ", document["feed"]["id"], "vintage", document["feed"]["vintage"])
print("window:    ", occurrence["window"], "from", occurrence["from"], "to", occurrence["to"])
print("solutions: ", occurrence["event_count"], "— peak", occurrence["peak_event_id"])
print("extent:    ", extent["min_latitude"], "-", extent["max_latitude"], "N",
      extent["min_longitude"], "-", extent["max_longitude"], "E")
for event in occurrence["events"][:10]:
    print("   ", event["time"], "M" + str(event["magnitude"]), event["event_id"])
print()
for limitation in document["limitations"]:
    print("*", limitation)'

# 3 — Your structure's own window, not the default: a 24-hour event window
#     collapses fewer solutions into one occurrence than a 72-hour one.
curl -sS "$CEDE_BASE_URL$FOOTPRINT?window=PT24H&min_magnitude=5.0" \
  -H "Authorization: Bearer $CEDE_API_KEY" > narrow.json

python3 -c 'import json
wide = json.load(open("footprint.json"))["footprint"]["occurrence"]
narrow = json.load(open("narrow.json"))["footprint"]["occurrence"]
print(wide["window"], "->", wide["event_count"], "solutions")
print(narrow["window"], "->", narrow["event_count"], "solutions at M>=",
      narrow["minimum_magnitude"])'

What the occurrence means#

A cat-in-a-box trigger pays per occurrence, and a mainshock's aftershocks are not separate occurrences. The rule is the aggregation window, measured from the first event of the cluster and never from the previous one — a chained rule would merge an unbounded aftershock sequence into a single occurrence, which is not what a 72-hour event window means.

That rule is the step between "the catalogue holds 2409 events" and "the backtest paid six times", and this route is where you can watch it happen:

The rule is time only, applied across the whole extract. Two solutions far apart inside the box can land in one occurrence, which is why every member is listed with its own position rather than summarised into a point — and why extent is a bounding box of solutions rather than a contour of anything.


What these documents are, and are not#

The published schemas are event-catalogue.v0.schema.json and event-footprint.v0.schema.json, both listed in the API contract document with every other response shape — validate against them while holding no Craton code.

Where to go next#