# API documentation

The StormTrust data service provides a versioned read boundary. Consumers do not depend on ingestion jobs, D1 tables, R2 keys, or Queue messages.

## Deployed data read API

The canonical [OpenAPI specification](https://stormtrust.net/openapi.json) defines the deployed read contract. The website exposes allowlisted `GET` and ` HEAD` routes. StormTrust Workers can use the same contract through a service binding to ` stormtrust-data`.

```http
GET /openapi.json
GET /v1/places/search?q={query}
GET /v1/storm-events
GET /v1/storm-events/{eventId}/revisions
GET /v1/storm-events/{eventId}/manifest
GET /v1/storm-events/{eventId}/revisions/{revisionId}/manifest
GET /v1/storm-events/{eventId}/frames/{productId}/{frameId}.png
GET /v1/storm-events/{eventId}/stream
GET /v1/data/status
```

The stream route upgrades to WebSocket. `StormStreamMessage` in the specification defines the JSON ` stream.ready` and ` storm.revision.ready` messages. The ` x-websocket-messages` extension connects those schemas to the route; it is a local documentation convention, not standard OpenAPI transport modeling. A text ` ping` receives a plain text ` pong`. Notices prompt authoritative reads and do not guarantee complete history or delivery of every publication.

Revision lists return the latest bounded subset in ascending **publication sequence**, which can differ from observation order when corrections arrive. `DataProductStatus` defines the existing snake\_case status fields and their null semantics. It reports latest discovered assets across live and benchmark events, not evaluated freshness or completeness. See [polling and triggers](/stormtrust/product/platform-and-data/polling-and-triggers/).

The source specification is `org/apps/data/openapi.json`. Data-service contract tests validate actual Worker HTTP bodies and WebSocket messages against its JSON Schemas, including malformed-payload rejection and late-correction order.

The service does not expose discovery, backfill, ingestion, or storage-control routes through the website. Legacy `/api/` and `/mrms/` paths remain temporary compatibility aliases.

Planned tenant API

The remaining resource groups describe the target tenant contract. They are not deployed until an application and a versioned OpenAPI document implement them.

## Versioning

The deployed read contract uses:

```txt
/v1/
```

Backward-incompatible changes require a new major API version or a governed compatibility path.

## Authentication

Client authentication may include tenant API tokens, OAuth for partner applications, and signed service credentials. The OpenAPI document declares the final schemes.

## Storm endpoints

```http
GET /v1/storms
GET /v1/storms/{stormId}
GET /v1/storms/{stormId}/revisions
GET /v1/storms/{stormId}/revisions/{revision}
GET /v1/storms/{stormId}/evidence
GET /v1/storms/{stormId}/timeline
GET /v1/storms/{stormId}/swaths
GET /v1/storms/{stormId}/impacts
GET /v1/storms/{stormId}/reports
```

## Weather endpoints

```http
GET /v1/weather/sources
GET /v1/weather/sources/{source}
GET /v1/weather/source-health
GET /v1/weather/products
GET /v1/weather/alerts
GET /v1/weather/reports
```

The tenant API should not expose provider-specific details unnecessarily.

## Property endpoints

```http
GET  /v1/properties
POST /v1/properties/search
GET  /v1/properties/{propertyId}
GET  /v1/properties/{propertyId}/impacts
GET  /v1/properties/{propertyId}/weather-history
GET  /v1/properties/{propertyId}/reports
GET  /v1/properties/{propertyId}/activities
```

## Impact endpoints

```http
GET /v1/impacts
GET /v1/impacts/{impactId}
```

Common filters include storm, minimum hail, confidence, geography, property type, priority, and eligibility.

## Monitoring endpoints

```http
GET    /v1/monitors
POST   /v1/monitors
GET    /v1/monitors/{monitorId}
PATCH  /v1/monitors/{monitorId}
DELETE /v1/monitors/{monitorId}

GET  /v1/alerts
GET  /v1/alerts/{alertId}
POST /v1/alerts/{alertId}/acknowledge
```

## Action plan endpoints

```http
GET  /v1/action-plans
POST /v1/action-plans
GET  /v1/action-plans/{planId}
POST /v1/action-plans/{planId}/approve
GET  /v1/action-plans/{planId}/zones
GET  /v1/action-plans/{planId}/assignments
```

## Field operations endpoints

```http
GET  /v1/territories
POST /v1/territories

GET  /v1/assignments
POST /v1/assignments

POST /v1/visits
GET  /v1/visits/{visitId}

POST /v1/inspections
POST /v1/evidence
POST /v1/outcomes
```

## CRM endpoints

```http
GET  /v1/leads
POST /v1/leads

GET  /v1/contacts
POST /v1/contacts

GET  /v1/opportunities
POST /v1/opportunities

GET  /v1/activities
POST /v1/activities
```

## Campaign endpoints

```http
GET  /v1/campaigns
POST /v1/campaigns
GET  /v1/campaigns/{campaignId}
POST /v1/campaigns/{campaignId}/approve
POST /v1/campaigns/{campaignId}/activate
GET  /v1/campaigns/{campaignId}/performance
```

Activation enforces authorization and eligibility.

## Report endpoints

```http
POST /v1/reports
GET  /v1/reports
GET  /v1/reports/{reportId}
GET  /v1/reports/{reportId}/manifest
POST /v1/reports/{reportId}/share
```

## Pagination

Collection endpoints use one pagination strategy. Cursor pagination is preferable for large mutable collections:

```json
{
	"data": [],
	"page": {
		"next": "cursor_abc"
	}
}
```

## Errors

Errors use stable machine-readable codes:

```json
{
	"error": {
		"code": "campaign_not_eligible",
		"message": "The campaign contains ineligible audience members.",
		"details": {},
		"requestId": "req_123"
	}
}
```

## Idempotency

Mutations with expensive or externally visible side effects support idempotency. Examples include report generation, campaign creation, external sends, imports, and webhook replay.

## Webhooks

Representative events include:

```txt
storm.created
storm.revised
storm.ended

impact.created
impact.updated

monitor.triggered
alert.created

action_plan.created
action_plan.approved

assignment.created
assignment.completed

inspection.completed

campaign.created
campaign.approved
campaign.activated

lead.created
opportunity.created
outcome.recorded

report.ready
```

Webhook envelopes carry stable identity and versioning:

```json
{
	"id": "evt_123",
	"type": "storm.revised",
	"version": "1",
	"createdAt": "2026-08-16T19:22:00Z",
	"tenantId": "tenant_123",
	"data": {}
}
```
