Skip to content
CRATON Docs Get a free API key

Getting started

Craton for AI agents

You may be an agent working for an underwriting team, a program designer, a broker, a corporate risk manager, or for a developer building for one of them. This page is written for you. It is short on ceremony and exact about requests, because the two things visiting agents most often lose time to are guessing hosts and guessing request bodies.

Craton is an API for catastrophe risk modeling: open models you can run on your own locations, one canonical risk object, an open schema and an open model registry. You can run several models over the same places and compare them, design a parametric trigger and replay it across forty seasons of recorded history, and build your own model from validated primitives, all through plain HTTP, no SDK.

On this page

The two hosts

Requests for documentation go to the docs host. Requests that create or read product state go to the API host. Nothing else exists.

Purpose Base
Documentation (this site; append .md to any page for raw markdown) https://docs.oncraton.com
API (everything under /signup, /objects, /structures, ...) https://api.oncraton.com

Fetching a docs path on the API host answers 401 or 404; it means the host is wrong, not that the page moved. Probe GET /health on the API base first: a 200 means the environment is up and taking requests.

One transport courtesy that is actually a requirement: send a descriptive User-Agent header. The edge in front of the public hosts refuses the anonymous default-library agents (Python-urllib, and friends) with a 403 before any of our code runs; a named agent passes.

A key in one call

Shell
curl -s -X POST https://api.oncraton.com/signup \
  -H 'Content-Type: application/json' \
  -d '{"label": "my-agent"}'

The 201 answer carries api_key.secret (cede_sk_...). The secret appears in that response only. Store it, then send it on every other call as Authorization: Bearer <secret>. Free sandbox plan, no payment details, no human in the loop. The body may also carry an email for the person who runs the agent. Unknown members are refused with a 422, not ignored: send email, label, both or nothing.

The verbs, precisely

Every request body shape below is documented on a page whose examples are extracted verbatim and executed against the live product on every change, so they cannot rot. Read the page before you compose the request; the 422s in our walk logs are all guessed bodies.

Verb Request The exact shapes
ingest POST /ingest (multipart file) quickstart
analyse POST /objects/{id}/analyse analyse
price POST /objects/{id}/price price
structure POST /objects/{id}/structures trigger
backtest POST /structures/{id}/backtest backtest
monitor POST /structures/{id}/monitoring monitoring
package POST /objects/{id}/package package

Objects come first: POST /objects stores the canonical risk object that every verb reads. The complete worked path from nothing to a priced, backtested structure is quickstart; composing a pricing model from registry primitives is model-builder.

Have an address and need a point? GET /geocode, with the address as q, answers with candidate coordinates, each carrying its precision and the public geocoder that produced it; pick one deliberately rather than taking the first, and show the attribution lines with it. The lookup text goes to the U.S. Census Bureau Geocoder or OpenStreetMap Nominatim, so send a location, never a person's name. One address per request: it is not a batch service (geocode).

Have schedule rows written in words ("2 sty wd frm apts, Houston TX")? POST /exposure-codes with {"rows": [...]}, up to 50 rows a request, answers with OED OccupancyCode and ConstructionCode per row. A field is coded only when it clears the confidence gate; read code (null below the gate) rather than proposed, and send the needs_review rows to a person. The rows go to an AI provider for coding, so send building descriptions, never a person's name (exposure-codes). Over MCP this is the code_exposure_rows tool.

Some schedule rows bundle several buildings ("Bldgs A-D, garden apts", "Main campus: 3 dorms, library, gym"). POST /multi-building-flags with the same {"rows": [...]} answers per row with the model's probability that the row covers more than one building and a status: flagged (it cleared the gate: split the row before modeling), below_gate (it leans that way; have a person read it), not_flagged or unanswered. It shares exposure coding's switch, caps and limits, and the rows go to the same AI provider (multi-building-flags). Over MCP this is the flag_multi_building_rows tool.

A 202 answer is an async job: poll the Location header (/jobs/{id}) until status is succeeded or failed; the result is embedded in the terminal job document. Everything else answers synchronously.

Why this platform rewards agent work

  • Determinism you can verify. Models make no network calls at run time; every result names the feed version and the SHA-256 of the exact bytes it read. Re-run a backtest a year later and it replays byte for byte.
  • Run ids are content addresses. A run id is derived from the document it identifies: check a result rather than trusting a caption.
  • Assumptions as fields. Model versions, data vintages, event sets and loadings arrive beside every number, machine-readable.
  • Docs that execute. Any example you read here ran against the live product on the current release. Raw markdown at /{page}.md; the index at /llms.txt.
  • One error envelope. Refusals are structured JSON with a code and a message (errors); 401 means the key, 422 means the body, 429 carries Retry-After, and rate-limit headers arrive on every answer.
  • Receipts. A published run you can reproduce digest-for-digest: receipts.

Connecting over MCP

Craton also serves its tools over the Model Context Protocol, from create_api_key through run_backtest and compose_model to run_climate_model and the data room's catalog, each dispatching against the REST API above. The endpoint is stateless Streamable HTTP, plain JSON, no auth dance: get a key with the create_api_key tool and pass it as the api_key argument (or send it as a Bearer header).

Endpoint: https://mcp.oncraton.com/mcp

Claude Code:

Shell
claude mcp add --transport http craton https://mcp.oncraton.com/mcp

Project .mcp.json:

JSON
{
  "mcpServers": {
    "craton": {
      "type": "http",
      "url": "https://mcp.oncraton.com/mcp"
    }
  }
}

Cursor (~/.cursor/mcp.json) takes the same object under mcpServers; VS Code (.vscode/mcp.json) uses the top-level key servers. If the endpoint does not answer, probe it with a POST ping and try again later.

The data room and the model lab

Two more surfaces open with the same key. The data room (https://data.oncraton.com) serves archived risk datasets whose publishers' terms allow commercial reuse: hazard event catalogs, flood and drought layers, weather ground truth, wildfire, exposure grids. The catalog at https://data.oncraton.com/catalog lists them, each with its license, the credit line to show when you reuse it, upstream publisher provenance and per-file digests. The model lab (https://lab.oncraton.com) runs pinned externally built open models: CLIMADA tropical-cyclone impact over the historical record, the same engine over the STORM synthetic event set for real return periods, an OpenQuake scenario earthquake, a real historical earthquake from its USGS ShakeMap through the same engine, annual earthquake losses for Europe and Turkey from the European Seismic Risk Model 2020 in OpenQuake, PiWind, the Oasis reference UK windstorm model, through the Oasis Loss Modelling Framework, and three lanes that read published hazard maps at your places: river flood, coastal flood and wildfire. Submit a run to https://lab.oncraton.com/runs with exposure points (or exposure: {"object_id": ...} to use a stored object's own schedule), per-event losses and an exceedance curve back, every run content-addressed and replayable by id. GET https://lab.oncraton.com/models lists each model's version, pinned inputs and caps. Lab results carry their own label: an externally built model run over pinned inputs, distinct from the registry's validated models. Over MCP these are the list_datasets, get_dataset, run_climate_model and get_lab_run tools. A worked, deterministic lab run, two 2004/2005 hurricanes against three Gulf coast exposure points, replaying to the same expected_annual_impact of 374012.3577728869 every time under model version climada-6.1.0-r3 (379135.58220932796 under climada-6.1.0-r2):

JSON
{
  "model": "climada-tropical-cyclone",
  "impact_function": "emanuel_2011",
  "hazard": {"basin": "NA", "years": [2004, 2005], "storms": ["KATRINA", "IVAN"]},
  "exposure": {"points": [
    {"lat": 29.95, "lon": -90.07, "value": 5000000},
    {"lat": 30.33, "lon": -87.14, "value": 3000000},
    {"lat": 27.95, "lon": -82.46, "value": 2000000}
  ]}
}

Send it as arguments.spec on a run_climate_model call, with your api_key beside it; equivalent specs share one content-addressed run, so a resubmit reads the stored result instead of recomputing.

The probabilistic lane, climada-tropical-cyclone-storm, prices against synthetic climatology instead of named history: {"model": "climada-tropical-cyclone-storm", "hazard": {"basin": "NA"}, "exposure": {"points": [...]}} runs your points against all 10,000 sample years of the STORM v4 event set (Bloemendaal et al. 2020, statistically resampled present-climate tropical cyclones); hazard.years takes fewer. Tracks that never come near your points are screened for cost, and the result counts them; a run whose exposure attracts more than the per-run track budget (caps.near_tracks on /models) is refused instantly with the levers named: fewer sample years, or tighter exposure clusters.

Both tropical-cyclone lanes take an impact_function: auto (the default: the US-calibrated Emanuel 2011 curve for places in the United States, the regionally calibrated Eberenz et al. 2021 RMSF curve elsewhere), emanuel_2011, eberenz_2021_tdr, eberenz_2021_rmsf or eberenz_2021_edr. Results from model versions climada-6.1.0-r2 (and -r3) and climada-6.1.0-storm-v4-r2 carry a result.metrics block (schema lab-metrics/1): average annual loss with its standard deviation and standard error, occurrence and aggregate exceedance (OEP and AEP) with tail value at risk, published only for return periods the sample supports ten times over, the spread across 1,000-year blocks, per-place shares, the largest events, full event and year loss tables, a damage-curve sensitivity, and the assumptions and warnings to read beside the figures. The history lane is a season-by-season replay: season totals, named storms with dates, and no return periods. Lab metrics explains every figure.

The seismic lane, openquake-scenario, answers a different question: not "what is my annual expectation" but "what would this one event do". {"model": "openquake-scenario", "rupture": {"magnitude": 6.5, "lat": 27.6, "lon": 84.4, "depth_km": 15}, "exposure": {"points": [...]}} runs one caller-defined rupture through the OpenQuake engine and answers per-point mean losses and ground motion over seeded fields. A single event carries no frequency, so there is no curve and no annual figure; the result says so itself. Points beyond 200km of the rupture come back unmodeled. vulnerability picks the curve: hazus_c1m_moderate_code (the default), hazus_c1m_high_code or hazus_c1m_pre_code (HAZUS 5.1 mid-rise concrete frames), or the engine's Nepal demonstration curves demo_nonengineered_concrete and demo_wood. From model version openquake-3.26.2-r2 the result's metrics block adds the loss ratio's spread across the fields, the geometric and arithmetic mean ground motion, and the same fields run through every curve.

The historical earthquake lane, openquake-shakemap, runs a real earthquake instead: {"model": "openquake-shakemap", "event": "northridge-1994", "exposure": {"points": [...]}} takes that earthquake's USGS ShakeMap, the shaking built from its own recordings, and answers the scenario lane's per-point mean losses over 100 ground-motion fields conditioned on it, each place with its loss spread and the ShakeMap's own shaking there. event is one of ten: northridge-1994, loma-prieta-1989, nisqually-2001, south-napa-2014, ridgecrest-2019, anchorage-2018, puerto-rico-2020, kaikoura-2016, kahramanmaras-2023 and tohoku-2011; /models lists each with its name, date, magnitude, region and ShakeMap rectangle. vulnerability takes the scenario lane's curves. Places outside the chosen ShakeMap come back unmodeled. Historical earthquakes has the details.

The probabilistic earthquake lane, openquake-esrm, answers the annual question for Europe and Turkey: {"model": "openquake-esrm", "building_class": "rc_infilled_frame_moderate_code_4", "exposure": {"points": [{"lat": 41.0082, "lon": 28.9784, "value": 10000000}]}} runs the European Seismic Risk Model 2020 (ESRM20, EFEHR, CC BY 4.0) in the OpenQuake engine: 10,000 sample years of earthquakes drawn from the ESHM20 source model over 20 sampled branches of its logic tree, site conditions from the ESRM20 site model, and one ESRM20 vulnerability function for every place, chosen from eleven building classes (GET /models lists them with plain labels). The event set is fixed by the model version, so the spec has nothing else to set; up to 500 places, and a place more than 5 km from the ESRM20 site model comes back unmodeled. The metrics block gives the average annual loss, OEP and AEP to 1 in 1,000, TVaR, the spread across 1,000-year blocks and the warnings that say how far to trust the tail. A run takes a few minutes; the lane's page has the method, the classes and worked numbers.

The Oasis lane takes the same shape with a smaller spec: {"model": "oasis-piwind", "samples": 10, "exposure": {"points": [...]}}, with points inside PiWind's footprint, answers with ground-up losses: an average annual loss, AEP/OEP exceedance curves and the largest events by mean loss, and from model version oasislmf-2.5.7-r2 the same result.metrics block. PiWind's hazard footprint is a demonstration-grade grid a few kilometers across in England (lat 52.734 to 52.795, lon -0.918 to -0.857); points outside it come back counted as unmodeled rather than refused, which is also how you verify your exposure actually landed in the footprint. A schedule with no point inside succeeds with every point unmodeled and no loss figure.

From oasislmf-2.5.7-r3 the same spec may carry terms, and Oasis's own financial module then adds insured and net-of-reinsurance losses beside ground-up: "terms": {"policy": {"place_deductible": 10000, "place_limit": 750000, "account_deductible": 25000, "account_limit": 1000000}, "reinsurance": {"quota_share": {"ceded_share": 0.3}, "layers": [{"attachment": 100000, "limit": 150000}]}}. Every field is optional, amounts are in the unit of your values, and up to three layers stack from the lowest up. result.metrics stays ground-up; result.perspectives.il and .ri are full metrics blocks for the insured and net views, and result.terms_summary says where the ground-up average went. The PiWind page has the fields, the caps and worked numbers.

Three lanes read published return-period hazard maps at each place instead of running an event set. {"model": "river-flood", "sector": "residential", "exposure": {"points": [...]}} reads JRC's global river flood depths (about 90 m, return periods 10 to 500 years) for the contiguous US, Puerto Rico and six international metros, and coastal-flood takes the same spec over WRI Aqueduct's coastal flood depths (about 1 km, 2 to 1,000 years, 2010 sea level), worldwide. Both turn depth into damage with the JRC depth-damage curve for the place's continent and your sector (residential, the default, commercial or industrial), and answer an average annual loss integrated over the published return periods, the loss at each of them, and depths per place. The maps are undefended: levees and sea walls are not modeled. {"model": "wildfire", "exposure": {"points": [...]}} reads the USFS FSim burn probability and flame-length maps (270 m) for the contiguous US, Alaska and Hawaii. No open, calibrated US wildfire damage function exists, so it gives no average annual loss: its only loss figure is a ceiling, burn probability times value. Places the maps do not reach come back unmodeled. Hazard-map lanes has the method, the sources and worked numbers.

Where Craton stops

Craton outputs technical prices, never quotes; it drafts terms, never offers; it cannot bind, issue, endorse, claim or settle. It holds no money and never touches paper. What you build here is analysis and drafts; execution belongs to the people you work for and their own capacity.

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