API Reference

SAR API gives you flood maps, dark vessel detections, and change analysis derived from free Sentinel-1 radar data. All endpoints return JSON. Authentication via X-API-Key header.

Overview

The API is split into two parts:

Authentication

Include your API key in every request as the X-API-Key header.

curl https://api.sarapi.io/v1/me \
  -H "X-API-Key: sw_your_key_here"

Get a free key at sarapi.io/#signup. No credit card required.

Base URL

Production https://api.sarapi.io

Rate limits & tiers

TierCalls/dayHistoryMax bboxWebhooksTiles
Free10030 days1°×1°
Developer5,0001 yearUnlimited
Pro50,0003 yearsUnlimited
EnterpriseUnlimitedUnlimitedUnlimited

When you exceed your daily limit you can use burst credits — one credit per call. Credits roll over for 90 days and can be topped up via billing/credits.

Errors

StatusMeaning
400Bad request — invalid parameters
401Missing or invalid X-API-Key
403Your plan does not include this feature
404Resource not found
410Resource expired (e.g. COG tiles past 14-day window)
429Daily rate limit exceeded, no credits remaining
502Upstream error (tile server, payment provider)

All errors return JSON: {"status":"error","code":"...","message":"..."}

GET /v1/analysis

Query analysis results (floods, vessels, oil spills, etc.) within a bounding box and date range. Results are paginated.

GET /v1/analysis 🔑 Auth required

Query parameters

ParameterTypeDescription
bboxrequiredBounding box as west,south,east,north in decimal degrees. Free tier limited to 1°×1°.
typeoptionalFilter by analysis type: flood, vessel, oil_spill, burn_scar, sea_ice, deforestation, construction. Omit or pass all for all types.
date_fromoptionalISO 8601 date string (e.g. 2024-01-01). Clamped to your tier's history limit.
date_tooptionalISO 8601 date string.
limitoptionalResults per page. Default: 100.
pageoptionalPage number. Default: 1.
Response200 OK
{
  "data": [
    {
      "id": "uuid",
      "type": "flood",
      "geometry": { "type": "Polygon", "coordinates": [...] },
      "confidence": 0.87,
      "acquired_at": "2024-06-15T10:32:00Z",
      "scene_id": "S1A_IW_GRDH_...",
      "properties": { "area_km2": 142.3 }
    }
  ],
  "meta": { "total": 48, "page": 1, "limit": 100, "pages": 1 }
}

GET /v1/latest

Returns the single most recent detection of a given type within a bounding box.

GET /v1/latest?bbox=...&type=flood 🔑 Auth required

Query parameters

ParameterTypeDescription
bboxrequiredwest,south,east,north
typerequiredAnalysis type (see above)
Response200 OK
{ "data": [ /* 0 or 1 result */ ] }

GET /v1/summary

Aggregate counts, total area, and last detection time per analysis type for a bbox and date range.

GET /v1/summary?bbox=...&date_from=...&date_to=... 🔑 Auth required
Response200 OK
{
  "flood": { "events": 12, "total_area_km2": 843.2, "last_detected": "2024-06-15T10:32:00Z" },
  "vessel": { "events": 234, "total_area_km2": 0, "last_detected": "2024-06-15T10:32:00Z" },
  "oil_spill": { "events": 3, "total_area_km2": 21.5, "last_detected": "2024-05-20T08:11:00Z" }
}

GET /v1/timeseries

Time-bucketed counts or total area for a given analysis type. Useful for charting trends.

GET /v1/timeseries?bbox=...&type=flood&metric=count&interval=week 🔑 Auth required

Query parameters

ParameterTypeDescription
bboxrequiredwest,south,east,north
typerequiredAnalysis type
metricoptionalcount (default) or area_km2
intervaloptionalday, week (default), or month
Response200 OK
{ "data": [ { "date": "2024-06-10T00:00:00.000Z", "value": 7 }, ... ] }

GET /v1/scenes

List SAR scenes that intersect a bounding box. Each scene includes a tile URL for map rendering.

GET /v1/scenes?bbox=...&date_from=...&date_to=... 🔑 Auth required
Response200 OK
{
  "data": [
    {
      "scene_id": "S1A_IW_GRDH_...",
      "acquired_at": "2024-06-15T10:32:00Z",
      "pass_direction": "ascending",
      "coverage": { "type": "Polygon", ... },
      "analysis_types": ["flood", "vessel"],
      "tile_url": "https://api.sarapi.io/v1/tiles/{scene_id}/{z}/{x}/{y}.png"
    }
  ]
}

GET /v1/coverage

Check whether a location has been imaged by Sentinel-1 and when the last acquisition was.

GET /v1/coverage?bbox=... 🔑 Auth required
Response200 OK
{
  "covered": true,
  "last_acquired": "2024-06-15T10:32:00Z",
  "next_expected": null,
  "pass_frequency_days": 6,
  "total_scenes": 84
}

Map tiles

Pro Enterprise   Render SAR imagery as XYZ map tiles.

GET /v1/tiles/{scene_id}/{z}/{x}/{y}.png?band=vv 🔑 Auth required

Returns a PNG tile. The band parameter accepts vv (default) or vh. Tiles are cached for 1 hour and expire 14 days after scene acquisition.

💡 Use the tile_url from /v1/scenes as a template — replace {z}, {x}, {y} with tile coordinates in your map library (Leaflet, Mapbox GL JS, etc).

POST /v1/subscriptions

Developer Pro Enterprise   Subscribe to real-time webhook alerts for new detections in an area.

POST /v1/subscriptions 🔑 Auth required

Request body

FieldTypeDescription
analysis_typerequiredflood, vessel, oil_spill, burn_scar, sea_ice, deforestation, construction, or all
bboxrequiredArray of 4 numbers: [west, south, east, north]
webhook_urlrequiredHTTPS URL that will receive POST events
secretoptionalSigning secret — included in X-SAR-Signature header of webhook events
curl -X POST https://api.sarapi.io/v1/subscriptions \
  -H "X-API-Key: sw_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "analysis_type": "flood",
    "bbox": [-0.5, 51.3, 0.3, 51.7],
    "webhook_url": "https://yourapp.com/hooks/sar",
    "secret": "whsec_..."
  }'
Response201 Created
{ "id": "uuid", "analysis_type": "flood", "webhook_url": "...", "active": true, "created_at": "..." }

GET /v1/subscriptions

List all webhook subscriptions for your API key.

GET /v1/subscriptions 🔑 Auth required

DELETE /v1/subscriptions/:id

Permanently delete a webhook subscription.

DELETE /v1/subscriptions/:id 🔑 Auth required

Returns 204 No Content on success.

Webhook payload format

When a new detection intersects your subscribed bbox, we send a signed POST to your webhook_url.

{
  "event": "detection.new",
  "subscription_id": "uuid",
  "analysis_type": "flood",
  "result": {
    "id": "uuid",
    "type": "flood",
    "geometry": { /* GeoJSON */ },
    "confidence": 0.91,
    "acquired_at": "2024-06-15T10:32:00Z",
    "properties": { "area_km2": 58.4 }
  },
  "sent_at": "2024-06-15T11:00:00Z"
}

If you provided a secret, verify the X-SAR-Signature: sha256=... header using HMAC-SHA256.

GET /v1/me

Returns your current plan, daily usage, credits, and limits.

GET /v1/me 🔑 Auth required
Response200 OK
{
  "tier": "free",
  "calls_today": 42,
  "calls_month": 312,
  "credits": 0,
  "limits": {
    "calls_per_day": 100,
    "history_days": 30,
    "bbox_max_degrees": 1
  }
}

POST /v1/billing/checkout

Create a Stripe Checkout session to upgrade your plan. Returns a redirect URL.

POST /v1/billing/checkout 🔑 Auth required

Request body

FieldTypeDescription
planrequireddeveloper or pro
Response200 OK
{ "url": "https://checkout.stripe.com/..." }

POST /v1/billing/credits

Purchase burst credits. Credits let you exceed your daily limit — one credit per extra call.

POST /v1/billing/credits 🔑 Auth required

Request body

FieldTypeDescription
packrequiredstarter (1,000 credits), growth (3,000 credits), pro (7,000 credits)
Response200 OK
{ "url": "https://checkout.stripe.com/..." }

GET /public/analysis

Sample of recent detections — no authentication required. Returns up to 500 results globally.

GET /public/analysis

GET /public/stats

Aggregate counts by detection type across the full dataset. No authentication required.

GET /public/stats
Response200 OK
{
  "flood": 1842, "vessel": 94210, "oil_spill": 312,
  "burn_scar": 58, "deforestation": 127, "sea_ice": 44,
  "construction": 91, "scenes": 2104
}