---
title: "Fetch a single signal by id"
method: GET
path: "/api/v1/signals/{id}"
---

# Fetch a single signal by id

`GET /api/v1/signals/{id}`

## Request

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

Costs 1 token(s) per request. Returns exactly one signal by its id (the `id` from a signals result). An id that has since been folded into another event resolves to that event, and `meta.merged_from_request` says so. Plan-dependent: on a plan without the full event detail (Free) the reported facts beyond the casualty counts are withheld, and each of the collection reasoning (with the GEOINT score), the market reasoning, the full source list and the relations opens on its own per plan; `plan_lock` names what was withheld and `plan_lock.section_plans` the plan that opens each part — a null there means not shown, not unknown (the same rule as the app and the public event pages). `signal.measured_same_place` lists the measurements recorded at the same place close in time (or, for a measured event, the reports there) — stored by fixed rules, never a confirmation; every plan sees that a pair exists and its kind, the times and the place name need the full event detail.

## Path parameters

- `id` string, uuid, required

## Response `200`

The signal.

- object
  - `signal` Signal: Stable public shape of a signal (additive changes only). 2026-09 corpus migration: the GDELT-era fields (goldstein_scale, avg_tone, num_mentions, integer ids) are gone — their inputs no longer exist — and the evidence ladder (stage / stage_reason) replaces the read-time observability derivations.
    - `id` string, uuid
    - `category` string, nullable
    - `title` string, nullable
    - `summary` string, nullable
    - `occurred_at` string, date-time, nullable: When the event happened, to the precision in occurred_at_precision. Null when reporting never said.
    - `occurred_at_precision` string, nullable: Granularity of occurred_at (day, hour, ...).
    - `occurred_at_basis` string, nullable: What occurred_at rests on — stated in the reporting, or inferred.
    - `first_reported_at` string, date-time, nullable
    - `last_reported_at` string, date-time, nullable: Most recent report. The start_date/end_date range filters on the UTC day of this field.
    - `location` string, nullable: Place name as resolved.
    - `location_label_level` 'locality' | 'block' | 'facility' | 'null', nullable: What `location` names.
    - `location_level` 'country' | 'admin1' | 'locality' | 'block' | 'facility' | 'null', nullable: How precisely the place was resolved. lat/lng are rounded to match — a country-level fix is not reported to metre precision.
    - `location_level_reported` string, nullable: What the reporting named, which can be coarser than what was resolved.
    - `country` string, nullable
    - `country_code` string, nullable: ISO 3166-1 alpha-2 of `country`.
    - `lat` number, nullable: null when `plottable` is false.
    - `lng` number, nullable: null when `plottable` is false.
    - `plottable` boolean: Whether the event is placed precisely enough to draw as a point. When false, lat/lng are null — the place is an area or the reports disagree on where it is; use `location` and `country`.
    - `geo_status` string, nullable
    - `stage` 'reported' | 'localized' | 'pinpointed' | 'null', nullable: How far the place is established: reported (country or province only, or not placeable) → localized (town or city) → pinpointed (street block or facility). Whether a satellite could see it is `collection.observable`; credibility is `reporting.credibility_best`.
    - `stage_reason` string, nullable: Why the place is not established more precisely — e.g. a named facility not yet found on the map (it can be looked up) versus no report naming anything finer.
    - `severity_score` number, nullable
    - `severity_band` integer, nullable: Coarse severity band.
    - `geoint_score` integer, nullable: How much a satellite look would add.
    - `impact_level` integer, nullable: Delta Impact Scale: the highest public threshold the reported figures cross (0 not a physical event … 5 = 1,000 or more killed or 800,000 or more displaced). Worked out by fixed rules, not by a model; null when the reports give no casualty or damage figure. Our own scale — see /methodology/scales. severity_score beside it is an AI reading.
    - `geoint_readiness` 'A' | 'B' | 'C' | 'D' | 'E' | 'null', nullable: Delta GEOINT Readiness: whether satellite imagery can check the event, looked up from three recorded facts (A = checkable now with free imagery … E = not checkable from orbit). Part of the collection section: null on a plan without it. Our own table — see /methodology/scales.
    - `escalation_trend` 'escalating' | 'de-escalating' | 'stable' | 'new' | 'null', nullable
    - `threat_vector` string, nullable
    - `impact_scope` string, nullable
    - `infrastructure_target` string, nullable
    - `cross_border_risk` boolean, nullable
    - `displacement_risk` integer, nullable
    - `confidence` string, nullable
    - `means` string, nullable: How it was carried out, as reported.
    - `means_basis` string, nullable
    - `targets_named` string[], nullable
    - `target_status` string, nullable
    - `target_effects` object[], nullable: Condition of each named target a report describes individually (the latest report stating it). A site with no entry has no stated condition — not "undamaged". disputed = another report states a different condition. The source reports are on the event thread (canonical_event.targets).
      - `name` string
      - `status` string
      - `note` string, nullable: A short verbatim quotation from a source report (at most 160 characters), given as evidence for the status. The reports are listed in the event's sources.
      - `disputed` boolean
    - `attributed_actor` string, nullable
    - `attribution_basis` string, nullable: What the attribution rests on. An attribution resting on one party's claim says so here.
    - `actors` string[], nullable
    - `casualties` object
      - `killed` integer, nullable
      - `injured` integer, nullable
      - `basis` string, nullable
      - `disputed` boolean: Reports disagree on the count. Not averaged — surfaced as a disagreement.
    - `measured` boolean: true = made from a measurement or an official record, not from reporting (see measured_kind). Its reporting counts are 0.
    - `measured_kind` 'thermal' | 'transit' | 'nightlight' | 'so2' | 'quake_exposure' | 'cyclone_exposure' | 'null', nullable: thermal = a heat source measured by satellite (GET /api/v1/thermal-anomalies returns the measurement under the same id); transit = ship transits through a strait or canal that left their own recent level (GET /api/v1/transit-anomalies returns the level of every measured place and, for one outside its usual range, this event id); nightlight = night lights over a city that fell below half of the city's own usual level, measured by satellite — the cause is not established by the record (GET /api/v1/nightlight-anomalies returns the measurement under the same id, and the level of every monitored city); so2 = sulfur dioxide clearly above the local background around a volcano with a current volcanic ash advisory, measured by satellite — not the size of an eruption, and not whether ash was present (GET /api/v1/so2-anomalies returns the measurement under the same id); quake_exposure = an earthquake recorded by USGS within a set distance of registered facilities — a seismic record and distances; it does not measure shaking or damage at any facility (GET /api/v1/quake-exposures returns the facilities and distances under the same id); cyclone_exposure = registered facilities and straits inside the tropical-storm-force wind radii of a U.S. National Hurricane Center forecast advisory, now or within 48 hours — a forecast for the Atlantic, eastern Pacific and central Pacific, not an observation of wind or damage (GET /api/v1/cyclone-exposures returns the advisory and the places under the same id). null for events made from reporting.
    - `measured_same_place_count` integer, nullable: Measurements recorded at the same place close in time (from a measured event: the reports there) — a heat source at the same facility, a transit change at the same strait, SO2 over the same volcano, a quake or cyclone at the same site. Stored by fixed rules, never a confirmation: the same place is not the same cause. null = could not be read (not 0). The pairs are on GET /api/v1/signals/{id} and the event thread (measured_same_place); linked_to=measured:any keeps only reports that have one.
    - `measured_same_place` object[], nullable: Only on GET /api/v1/signals/{id}: the pairs counted by measured_same_place_count. withheld = true keeps the pair and its kind but not the times, the gap or the place name (they need the full event detail).
      - `event_id` string, uuid: The other event of the pair.
      - `title` string, nullable
      - `category` string, nullable
      - `other_is_measured` boolean
      - `measured_kind` 'thermal' | 'transit' | 'nightlight' | 'so2' | 'quake_exposure' | 'cyclone_exposure' | 'null', nullable
      - `basis` 'same_entity' | 'same_volcano'
      - `counterpart` 'report' | 'aviation_advisory': aviation_advisory = the other event is only volcanic ash advisories (an official aviation notice), not reporting.
      - `entity_id` string, uuid, nullable
      - `entity_name` string, nullable
      - `place_key` string, nullable
      - `measured_at` string, date-time, nullable
      - `report_at` string, date-time, nullable
      - `hours_after_measurement` number, nullable: Report time minus measurement time, in hours (positive: the measurement came first).
      - `withheld` boolean
    - `occurrence_status` 'reported' | 'claimed' | 'disputed' | 'null', nullable: How far the event itself is established. claimed = the only party stating it is the side saying it carried it out. disputed = the side said to have been hit, or an authority, denies it. null = not yet assessed (NOT "confirmed"). Who claimed and who denied are on the event thread (canonical_event.occurrence).
    - `reporting` object
      - `member_count` integer: Reports folded into this one event.
      - `distinct_hosts` integer: Distinct outlets among them. Syndication is not collapsed — breadth of carriage, not independence.
      - `distinct_texts` integer, nullable: Distinct texts among them: outlets carrying the same wire copy count once. Not a count of independent confirmations — different texts can rest on the same single statement. null = not yet counted.
    - `collection` object: What a satellite could do about it.
      - `level` string, nullable
      - `sensor` 'sentinel-2' | 'sentinel-1-sar' | 'viirs-thermal' | 'planet' | 'vhr-optical' | 'multi-sensor' | 'none' | 'null', nullable
      - `analysis` string, nullable
      - `niirs` string, nullable
      - `target` string, nullable
      - `reason` string, nullable
      - `aoi` number[], nullable: [minLon, minLat, maxLon, maxLat].
      - `gap` string, nullable: What stands in the way of a look (cloud, night, revisit).
      - `observable` boolean, nullable: Whether a satellite could see it: the effect is large enough to show from orbit (observability) AND the place is established finely enough to frame it (0.3 m marks need a street block or facility). null = not assessed, which is not "no".
      - `observable_reason` string, nullable: Why: not_assessed / nothing_visible_from_orbit / needs_<stage>_for_observability_<n> / visible_at_observability_<n>.
      - `observability` number, nullable: NOT a probability: the coarsest resolution at which the effect still shows. 3 = visible at 10 m (flooding, burn scars), 2 = 3 m (several damaged buildings), 1 = 0.3 m (a single building), 0 = nothing shows from orbit. Higher means a coarser image suffices — lower means the location has to be known more precisely before anything can be pointed at it.
    - `market_impact` string[], nullable
    - `market_note` string, nullable
    - `market_exposure` object: The evidence chain behind market_impact. basis="evidence_chain" means each tag carries its own evidence.
      - `tags` string[]
      - `evidence` object[]
      - `basis` 'evidence_chain' | 'legacy_tags' | 'unsubstantiated' | 'none'
    - `quality` object
      - `status` string, nullable
      - `score` number, nullable
      - `issues` string[], nullable
    - `authenticity_concern` string, nullable
    - `created_at` string, date-time, nullable: When this event was first opened. created_since filters on it.
    - `last_updated_at` string, date-time, nullable: When it was last refolded. updated_since filters on it.
    - `assessed_at` string, date-time, nullable: When the collection assessment last ran. Null means it has not run — not that nothing is observable.
    - `sequence_parents` object[]: When this event is one incident in a larger sequence (a series of attacks, a protest movement), the top-level sequence it belongs to — the same "Part of …" line the Watchfloor list shows. Empty for most events. Read the sequence and its other incidents with get_event_thread (sequence).
      - `id` string, uuid, required
      - `title` string, nullable, required
    - `plan_lock` object, nullable: What the key owner's plan withholds from this signal (null when nothing is). Without the full event detail the reported facts beyond casualty counts, and — each by its own plan — the collection reasoning, GEOINT score and market reasoning, are null here because they are not shown — not because they are unknown.
      - `sections` string[]
      - `required_plan` string, nullable: The cheapest plan that opens the first withheld part (derived from the current plans; null when no plan does).
      - `section_plans` object: For each withheld section, the cheapest plan that opens it — what happened (facts, places) opens before the evidence (sources, collection, markets, relations).
      - `note` string
  - `meta` 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.
- `404`: 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)
