Public API Reference

Global Chokepoints Alerts API

Real-time JSON data on the operational status of the Strait of Hormuz. All /v1 endpoints are public, CORS-open, and licensed under CC-BY-4.0. No API key required for most uses.

CORS allow-allEdge cachedCC-BY-4.0No SDK — plain JSON

Interactive Playground

Try every endpoint live — send real requests, inspect responses, and explore schemas in the browser.

Open Playground

Overview

The API is deployed on Cloudflare Pages Edge Workers. All routes run globally with no cold starts and multi-layer KV caching. The base URL is:

text
https://strait-of-hormuz-monitor.pages.dev

Rate limits

There are no hard programmatic rate limits today. Cloudflare edge caching means most requests are served from cache within a 30–300 s TTL window; upstream sources are not hit per-request. Fair use is expected — treat each endpoint as a polling interval, not a real-time stream.

Attribution

When displaying data from /v1/* endpoints, include the attribution string from the license field: “Global Chokepoints Alerts” with a link to https://strait-of-hormuz-monitor.pages.dev.

Route families

PrefixPurposeAuthCORS
/v1/*Public intelligence APIOptional keyAllow-all
/api/*Internal dashboard data feedsNoneSame-origin
/feed.xmlRSS 2.0 event feedNoneAllow-all

Authentication

GET requests to /v1/* are always public — no key, no header, no signup. CORS preflight (OPTIONS) and HEAD are also unauthenticated.

Authentication only applies to non-GET methods on /v1/* and is enforced only when the deployment's V1_API_KEY environment variable is set. If a key is required, send it in either form:

bash
# Option A — x-api-key header
curl -X POST -H "x-api-key: YOUR_KEY" https://strait-of-hormuz-monitor.pages.dev/v1/...

# Option B — Bearer token
curl -X POST -H "Authorization: Bearer YOUR_KEY" https://strait-of-hormuz-monitor.pages.dev/v1/...

Requests without a valid key on a gated method receive 401 Unauthorized. Internal /api/* routes are always same-origin and have no key requirement.

Public v1 API

Three endpoints provide everything needed to build embeds, dashboards, or alerting integrations. All responses include a license field and a docs pointer back to /methodology.

GET/v1/status30 s cacheCurrent strait status

The primary endpoint. Returns the computed operational state (OPEN / PARTIALLY_CLOSED / CLOSED), a 0–100 threat score, confidence value, and a human-readable reason string.

Response fields

FieldTypeDescription
stateenumOPEN | PARTIALLY_CLOSED | CLOSED
tensionLevelenumNORMAL | ELEVATED | CRITICAL
tensionIndexinteger0–100 composite threat score (see /methodology)
confidencenumber0..1 based on source diversity and event density
reasonstringHuman-readable explanation of current state
reasonUrlstring?URL of the driving source article, if any
brentobject?{ price, change, changePercent } — null if feed is down
events24hintegerDistinct classified events in the past 24 hours
asOfISO 8601Timestamp of this computation
sourcesstring[]Source names contributing to current state

Examples

bash
curl https://strait-of-hormuz-monitor.pages.dev/v1/status
javascript
const res  = await fetch('https://strait-of-hormuz-monitor.pages.dev/v1/status');
const data = await res.json();

console.log(data.state);        // "OPEN"
console.log(data.tensionIndex); // 42
console.log(data.reason);       // "Maritime traffic operational. ..."
GET/v1/events60 s cacheGeopolitical event timeline

Classified events aggregated from CNN, BBC, Al Jazeera, Reuters (via Google News), and Google News RSS. Events are filtered by Hormuz/Iran/maritime keywords and scored by severity.

Parameters

NameInTypeRequiredDescription
limitqueryintegeroptionalMax events to return (1–100, default 30)
sincequeryISO 8601optionalReturn only events at or after this timestamp — useful for incremental polling

Response fields

FieldTypeDescription
events[].idstringUnique event identifier (URL-derived hash)
events[].dateISO 8601Event publication timestamp
events[].titlestringHeadline
events[].descriptionstringLead paragraph or snippet
events[].categoryenumincident | military | diplomatic | economic
events[].severityenumlow | medium | high | critical
events[].sourcestringPublisher name (e.g. "BBC")
events[].urlstringOriginal article URL
countintegerTotal events returned
generatedAtISO 8601Response generation time

Examples

bash
# Latest 10 events
curl "https://strait-of-hormuz-monitor.pages.dev/v1/events?limit=10"

# Incremental poll — events since last check
curl "https://strait-of-hormuz-monitor.pages.dev/v1/events?since=2026-05-14T06:00:00Z"
javascript
// Incremental polling
let cursor = new Date(Date.now() - 60_000).toISOString();

setInterval(async () => {
  const url = `https://strait-of-hormuz-monitor.pages.dev/v1/events?limit=20&since=${cursor}`;
  const { events, generatedAt } = await fetch(url).then(r => r.json());
  cursor = generatedAt;
  events.forEach(e => console.log(e.severity, e.title));
}, 60_000);
GET/v1/metrics60 s cacheMarkets, weather and event metrics

Aggregates Brent crude, WTI, Henry Hub natural gas, marine weather at Bandar Abbas, and 24-hour event delta. Any subsystem that is unreachable returns null rather than failing the whole response.

Response fields

FieldTypeDescription
markets.brentTicker|nullBrent crude (USD/bbl). See Ticker type below.
markets.wtiTicker|nullWest Texas Intermediate (USD/bbl)
markets.natgasTicker|nullHenry Hub natural gas (USD/MMBtu)
weather.temperatureCnumberAir temperature at Bandar Abbas approach (°C)
weather.windobject{ speedKn, direction, directionDeg }
weather.seaobject{ waveHeightM, wavePeriodS, windWaveM, swellM }
weather.navRisknumber0–100 navigational risk composite
weather.navRiskLabelenumCALM | MODERATE | ROUGH | SEVERE
events.last24hintegerClassified events in the past 24 hours
events.prev24hintegerEvents in the preceding 24-hour window
events.deltaintegerDifference: last24h − prev24h

Examples

bash
curl https://strait-of-hormuz-monitor.pages.dev/v1/metrics
javascript
const { markets, weather, events } = await fetch('https://strait-of-hormuz-monitor.pages.dev/v1/metrics').then(r => r.json());

if (markets?.brent) {
  console.log(`Brent: ${markets.brent.price} (${markets.brent.changePercent}%)`);
}
if (weather) {
  console.log(`Wind: ${weather.wind.speedKn}kn ${weather.wind.direction} · NavRisk: ${weather.navRiskLabel}`);
}

Data Feed Routes

These routes are used by the dashboard internally and are same-origin by default. They are documented here for transparency and local development. Each one implements a multi-source fallback chain — they never return 502 while any cached data exists.

RouteSources (priority order)Cache TTL
/api/brentYahoo Finance → Stooq CSV → EIA → module cache → KV5 min
/api/marketsEIA (Brent/WTI) + FRED (Henry Hub) → Yahoo Finance5 min
/api/timeline7 RSS feeds (CNN, BBC, Al Jazeera, Google News) → KV60 s
/api/newsGDELT v2 Doc API → KV fallback5 min
/api/weatherOpen-Meteo Forecast + Marine → KV15 min
/api/vesselsdata/vessels.json (AIS sidecar) → KV fallback2 min
/api/portwatchIMF PortWatch → KV6 h
/api/healthParallel probes (Yahoo, GDELT, RSS, Open-Meteo)30 s

Subscriptions

Users can subscribe to receive an email when the strait state changes (e.g. OPEN → PARTIALLY_CLOSED). The alert system uses Cloudflare D1 for storage and Resend for transactional email.

POST/api/subscribeRegister email for status alerts

Inserts an unconfirmed subscription and sends a confirmation email. Idempotent for unconfirmed addresses — resends the confirmation link.

Parameters

NameInTypeRequiredDescription
emailbodystringrequiredEmail address to subscribe
turnstileTokenbodystringoptionalCloudflare Turnstile token — required when TURNSTILE_SECRET_KEY is configured

Examples

bash
curl -X POST https://strait-of-hormuz-monitor.pages.dev/api/subscribe \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com"}'

GET /api/confirm?token=<token> — confirms subscription; redirects to /?subscribed=1

GET /api/unsubscribe?token=<token> — deletes subscription; redirects to /?unsubscribed=1

Types reference

StraitStatus

typescript
type StraitStatus =
  | 'OPEN'             // traffic operating normally
  | 'PARTIALLY_CLOSED' // disruption, diversion, or elevated incident signals
  | 'CLOSED'           // closure keyword detected in recent event headlines

TensionLevel & threat score

typescript
type TensionLevel = 'NORMAL' | 'ELEVATED' | 'CRITICAL'

// tensionIndex is a 0–100 composite:
//   timeline_score (50%) — severity-weighted events in the last 24 h
//   market_score   (50%) — Brent Δ% mapped to 0–100 above +2%

// Thresholds
// tensionIndex >= 80 or state === 'CLOSED'  → CRITICAL
// tensionIndex >= 40 or state !== 'OPEN'    → ELEVATED
// otherwise                                 → NORMAL

TimelineEvent

typescript
interface TimelineEvent {
  id:          string
  date:        string       // ISO 8601
  title:       string
  description: string
  category:    'incident' | 'military' | 'diplomatic' | 'economic'
  severity:    'low' | 'medium' | 'high' | 'critical'
  source:      string       // publisher name, e.g. "BBC"
  url?:        string       // original article URL
}

Ticker (markets)

typescript
interface Ticker {
  price:         number
  change:        number
  changePercent: number
  history:       { date: string; price: number }[]  // 7-day spark
  asOf:          string       // ISO 8601
  label:         string       // e.g. "Brent Crude"
  symbol:        string       // e.g. "BZ=F"
  unit:          string       // e.g. "USD/bbl"
  provider:      string
  stale?:        boolean
  error?:        string
}

OpenAPI specification

A machine-readable OpenAPI 3.0.3 spec is served at /api/openapi. It can be imported into Postman, Insomnia, or any OpenAPI-compatible tool. An interactive Scalar viewer is available at /api-reference.

bash
# Download spec
curl https://strait-of-hormuz-monitor.pages.dev/api/openapi -o openapi.json

# Import into Postman (CLI)
postman import openapi.json
Prefer a visual explorer? The Scalar playground lets you send live requests directly from the browser.
Open Playground →

The spec is regenerated on each deploy and cached for 1 hour at the edge.