Off-Nadir Delta

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

  1. Follow meta.next_cursor until has_more is false (the SDK does this with signals.iterate).
  2. 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.

← All recipes

From headline to satellite evidence

One connected intelligence workflow across four surfaces — free to start, no GIS software or remote-sensing background required.