---
title: "SO2 anomalies: sulfur dioxide above the local background around a volcano"
method: GET
path: "/api/v1/so2-anomalies"
---

# SO2 anomalies: sulfur dioxide above the local background around a volcano

`GET /api/v1/so2-anomalies`

## Request

- Base URL: `https://offnadir-delta.com`
- URL: `https://offnadir-delta.com/api/v1/so2-anomalies`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

3 tokens minimum per request; above 30 rows, 1 token per 10 rows returned (rounded up) — the same rule as a page of signals, and the same plan window applies (meta.window_clamp says when it was cut). An SO2 anomaly is a satellite measurement, not a report: sulfur dioxide measured by Copernicus Sentinel-5P (TROPOMI, near-real-time) clearly above the local background around a volcano. Only volcanoes with a recent volcanic ash advisory are checked. Pixels within 0.5 degrees of the volcano are compared with the ring out to 2 degrees (quality value 0.5 or better): a record is made when at least 10 pixels exceed the ring's median by 5 times its spread and 1 Dobson Unit, and that is at least 3 times what the ring itself would predict. One record per volcano per UTC day. Each record carries the volcano (name and position), sensed_at (the start of the satellite overpass), peak_du (the largest total vertical column near the volcano, in Dobson Units), background_du and background_spread_du (the ring's median and spread), pixels_over and pixels_expected (how many near pixels stood out, against how many the ring would predict), pixels_near and granule (the product file the values were read from). Every record is also an event (same event_id as GET /api/v1/signals with categories=so2_anomaly, where it carries measured=true and measured_kind=so2), so the event endpoints work on it. related_events lists events tied to this one by a stored relation — nothing is inferred when the record is read, so it is usually empty; it needs a plan with event relations (otherwise null, and meta.notes says so). The detail — which volcano, the column amounts, the pixel counts, the granule and the summary — needs a plan with the full event detail. Without it every record still returns that it was recorded, when, the position and its kind, with detail_withheld=true, a placeholder title and null in the withheld fields (meta.detail_included and meta.detail_required_plan say so); the same records in GET /api/v1/signals carry the placeholder title too. meta.definition carries the thresholds, meta.notes what the record does and does not establish, and meta.attribution the source credit, which must be shown with the data. Cursor pagination via meta.next_cursor.

## Query parameters

- `bbox` string
- `start_date` string, date
- `end_date` string, date
- `limit` integer
- `cursor` string

## Response `200`

A page of records, newest first.

- object
  - `meta` object
  - `so2_anomalies` object[]

## Other responses

- `400`: Error response with a stable machine-readable code.
- `401`: Error response with a stable machine-readable code.
- `402`: Error response with a stable machine-readable code.
- `403`: Error response with a stable machine-readable code.
- `429`: Error response with a stable machine-readable code.

---

[API](https://skmtc.dev/offnadir-delta/apis/off-nadir-delta-api.md) · [All operations](https://skmtc.dev/offnadir-delta/apis/off-nadir-delta-api/llms.txt) · [OpenAPI document](https://skmtc.dev/offnadir-delta/apis/off-nadir-delta-api/revisions/5cf3f2bed5a2?raw)
