Read everything — cursor pagination, then server-side aggregates
A first page is not the result set. You want every matching signal, and then counts that the server computes more cheaply than you can.
Steps
- Follow meta.next_cursor until has_more is false (the SDK does this with signals.iterate).
- Ask for the same window as aggregates: stats (counts by category/day) and hotspots (where activity concentrates).
REST
Authenticate with Authorization: Bearer ond_… (create a key at /account/api). Try any of these live in the Playground.
Full result set (cursor loop)
bash
# Returns the first page (up to `limit`, max 500). If the response's
# meta.has_more is true, repeat with &cursor=<meta.next_cursor> for the rest.
curl "https://offnadir-delta.com/api/v1/signals?bbox=22%2C44%2C40%2C53&days=14&min_severity=6" \
-H "Authorization: Bearer ond_YOUR_API_KEY"Aggregate stats
bash
curl "https://offnadir-delta.com/api/v1/signals/stats?bbox=22%2C44%2C40%2C53&days=14" \
-H "Authorization: Bearer ond_YOUR_API_KEY"Hotspots
bash
curl "https://offnadir-delta.com/api/v1/signals/hotspots?bbox=22%2C44%2C40%2C53&days=14" \
-H "Authorization: Bearer ond_YOUR_API_KEY"Python
This is the runnable example shipped with the SDK (pip install offnadir-delta, then set OFFNADIR_DELTA_API_KEY).
python
"""Iterate every signal across pages, then pull aggregate stats and hotspots."""
from collections import Counter
from offnadir_delta import Client
AOI = [22.0, 44.0, 40.0, 53.0]
def main() -> None:
with Client() as client:
# Auto-pagination: follows the cursor until exhausted (each page is metered).
by_category: Counter[str] = Counter()
for signal in client.signals.iterate(bbox=AOI, days=14, min_severity=6):
by_category[signal.category or "unknown"] += 1
print("High-severity signals by category:")
for category, count in by_category.most_common():
print(f" {category}: {count}")
# Cheaper: server-side rollups (1 token) instead of walking every row.
stats = client.signals.stats(bbox=AOI, days=14)
print(f"\nTotal events (server stats): {stats.meta.total}")
# Grid-aggregated hotspots.
hotspots = client.signals.hotspots(bbox=AOI, days=14, precision=0.5)
print("\nTop hotspots:")
for h in hotspots.hotspots[:5]:
print(f" ({h.lat:.2f}, {h.lng:.2f}) count={h.count} max_severity={h.max_severity}")
if __name__ == "__main__":
main()
MCP
Connect once, from any MCP client:
bash
claude mcp add --transport http off-nadir-delta \
https://offnadir-delta.com/api/v1/mcp \
--header "Authorization: Bearer ond_..."The tools this workflow uses: query_signals, query_stats, query_hotspots. See the full roster at /docs/mcp.
From headline to satellite evidence
One connected intelligence workflow across four surfaces — free to start, no GIS software or remote-sensing background required.