# 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 building insurance software: one canonical risk object,
seven verbs, an open schema, an open model registry. You can design a
trigger-based product, replay it across forty seasons of pinned history,
read a technical price with every assumption attached as a field, compose a
pricing model from validated primitives, and watch a live structure — all
through plain HTTP, no SDK.

## 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://altier.ridgehead-hamlet.ts.net:8472` |

Fetching a docs path on the API host answers 401 or 404; it means the host
is wrong, not that the page moved. The API host is reachable inside the
operator's tailnet today; `api.oncraton.com` follows once its edge
protections land, and this page will name it the day it does.

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

```
curl -s -X POST https://altier.ridgehead-hamlet.ts.net:8472/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. Unknown members in the body are refused with a 422,
not ignored — send `label` 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 —
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) | [ingest](/ingest.md) |
| analyse | `POST /objects/{id}/analyse` | [analyse](/analyse.md) |
| price | `POST /objects/{id}/price` | [price](/price.md) |
| structure | `POST /objects/{id}/structures` | [trigger](/trigger.md) |
| backtest | `POST /structures/{id}/backtest` | [backtest](/backtest.md) |
| monitor | `POST /structures/{id}/monitoring` | [monitoring](/monitoring.md) |
| package | `POST /objects/{id}/package` | [package](/package.md) |

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](/quickstart.md); composing a pricing
model from registry primitives is [model-builder](/model-builder.md).

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](/llms.txt).
- **One error envelope.** Refusals are structured JSON with a code and a
  message ([errors](/errors.md)); 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](/receipts.md).

## Connecting over MCP

Craton also serves its tools over the Model Context Protocol — thirteen
tools from `create_api_key` through `run_backtest` to `compose_model`, 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://altier.ridgehead-hamlet.ts.net:8475/mcp`

Claude Code:

```
claude mcp add --transport http craton https://altier.ridgehead-hamlet.ts.net:8475/mcp
```

Project `.mcp.json`:

```json
{
  "mcpServers": {
    "craton": {
      "type": "http",
      "url": "https://altier.ridgehead-hamlet.ts.net:8475/mcp"
    }
  }
}
```

Cursor (`~/.cursor/mcp.json`) takes the same object under `mcpServers`;
VS Code (`.vscode/mcp.json`) uses the top-level key `servers`. The host
above is reachable inside the operator's tailnet today; a public hostname
follows with the production deployment, and claude.ai custom connectors
need that public hostname.

## 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.
