Changes to the Event Intelligence REST API and the MCP server. Newest first.
We aim not to break integrations. Additive, backward-compatible changes — new endpoints, new MCP tools/resources, new optional parameters, and new response fields — may ship without notice, so parse responses tolerantly (ignore unknown fields). Any breaking change is announced here first. The machine-readable contract is /api/v1/openapi.json, and the MCP server reports its version in the initialize response (registry id com.offnadir-delta/mcp).
MCP server 5.2.0 and Python SDK 4.1.1: a page of events is now charged by the rows it returns — 1 token per 10 rows (rounded up), with a minimum of 3 tokens per request. It was a flat 3 tokens a page whatever its size. This applies to GET /api/v1/signals and MCP query_signals, to the measured-event readers (thermal-anomalies, nightlight-anomalies, so2-anomalies, quake-exposures, cyclone-exposures) and to GET /api/v1/developments and MCP query_developments; GET /api/v1/transit-anomalies stays at a flat 3. Before the query runs, the balance must cover the most the requested limit can cost (402 otherwise, and a smaller limit costs less); meta.tokens.charged reports what the page cost. In MCP _meta.pricing_contract, query_signals and query_developments are now objects (minimum, rows_per_token, maximum) instead of a number.
MCP server 5.0.0 and Python SDK 4.0.0 (breaking): imagery is now checked only for events on your Watchlist. A signal no longer carries imagery (GET /api/v1/signals, MCP query_signals, assess_signal), and GET /api/v1/developments and MCP query_developments no longer return or accept the imagery axes (naming one returns 400 with the replacement). Read imagery from the watch: GET /api/v1/watches/{id} and MCP get_watch return signal.imagery_check — whether imagery is being checked and, if not, why. Creating a watch stays free. On plans that include the imaging recommendation, a watched event's imagery is then checked automatically at 1 token per watch per day, until before and after scenes are found or 14 days after the first report; a day without enough tokens is skipped and not charged. On other plans imagery is not checked and nothing is charged.
Night-light anomalies now list the monitored cities (Python SDK 3.2.0; MCP unchanged). GET /api/v1/nightlight-anomalies returns cities beside the records: every city whose night lights are measured, anomaly or not, with status (usual, below, or not_judged with a reason — too cloudy, not yet comparable, or too dim for the rule), level (the latest judged night as ratio_to_usual / percent_of_usual of the city's own usual level, with observed_share and provisional), the recent nights and baseline_nights. The list is the same on every page and is not filtered by bbox or dates; meta.cities carries the count and what usual means. In the Python SDK it is page.cities (model NightlightCity), and page.below picks the cities whose latest judged night was below half. The level needs a plan with the full event detail — without it each city is still returned with its name and position and detail_withheld=true. Brightness values are not returned. The same cities are on the Watchfloor map and the map page as crescent marks (Layers: Night lights).
Four more kinds of measured event, each with a category of its own and an endpoint of its own. Night-light anomalies (category nightlight_anomaly, GET /api/v1/nightlight-anomalies, client.nightlight_anomalies in the Python SDK): nights on which the satellite-measured lights over a listed city were below half of the city's own usual level. SO2 anomalies (so2_anomaly, GET /api/v1/so2-anomalies, client.so2_anomalies): sulfur dioxide measured by Sentinel-5P clearly above the local background around a volcano with a current volcanic ash advisory. Earthquakes near facilities (quake_exposure, GET /api/v1/quake-exposures, client.quake_exposures): U.S. Geological Survey earthquake records with registered facilities within a magnitude-dependent distance of the epicentre. Cyclone wind exposure (cyclone_exposure, GET /api/v1/cyclone-exposures, client.cyclone_exposures): 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, for the Atlantic, eastern Pacific and central Pacific. The first two are satellite measurements; the third is a seismic record and distances; the fourth is an official forecast, not an observation. None states a cause, shaking or damage. Every record is also an event: GET /api/v1/signals and MCP query_signals return them under those categories with measured: true and the matching measured_kind. The four endpoints take bbox, start_date, end_date, limit and cursor, and cost the same as a page of signals. The detail of a record (which city, volcano, facilities or storm, and the values) needs a plan with the full event detail; without it records return that one was made, when, where and its kind.
Measured events now have categories of their own, and origin is retired (MCP 4.0.0, Python SDK 3.0.0). A thermal anomaly has the category thermal_anomaly and a transit anomaly (ship transits or port calls that left their own recent level) has transit_anomaly; until now they were filed under infrastructure or other and under maritime, so those three categories no longer include them. Select them like any other event with the categories parameter of GET /api/v1/signals, MCP query_signals and signals.list in the SDK. The origin parameter is no longer accepted on any of the three: sending it returns 400 naming categories as the replacement. measured and measured_kind on each signal, GET /api/v1/thermal-anomalies and GET /api/v1/transit-anomalies are unchanged. On the Watchfloor both appear under Category; the Layers panel no longer has switches for them.
Transit anomalies: GET /api/v1/transit-anomalies (and client.transit_anomalies in the Python SDK, 2.5.0) returns every strait and canal where ship transits are measured — 28 places — in one response: whether the 7-day average of transits is within its usual range, and its level as an index computed by this product, with the usual level set to 100 (index, change, tanker_index, and revised when the underlying figure changed after it was first recorded). A place outside its usual range also carries since when, for how many days, and the id of the event recorded for it — the same event GET /api/v1/signals returns with origin=transit. A measurement, not a report: it says the number of ships changed and never why. The measurements are updated weekly, so a change becomes visible 4 to 11 days after it happens. Takes no parameters; same cost as a page of signals. The numbers need a plan with the full event detail; without it each place still returns its status, since when and the event id, with detail_withheld=true. Not an MCP tool: in a conversation, query_signals with origin=transit and get_entity cover it.
The transit levels of a strait or canal on GET /api/v1/entities/{entityId} (and MCP get_entity) are now an index instead of ship counts. Each level carries index (the 7-day average with the usual level set to 100), change, tanker_index and revised (true when the underlying figure changed after it was first recorded). mean_per_day, baseline_per_day, tanker_mean_per_day, tanker_baseline_per_day and revised_from are no longer returned. The summaries of transit anomaly events state the change against the usual level as a percentage rather than as ship counts.
Thermal anomalies: GET /api/v1/thermal-anomalies (and client.thermal_anomalies in the Python SDK) returns heat sources measured by satellite — near registered facilities, and strong isolated ones at night away from any facility (that kind does not rule out vegetation fires) — each far above the strongest detection at the same spot in the 21 days before — with its strength, the earlier level, the satellites, the facility and the distance. A measurement, not a report: it never states a cause. Every record is also an event; GET /api/v1/signals and MCP query_signals take origin (all / measured / reported), and each signal carries measured. Same cost and plan window as a page of signals. The measurement detail (which facility or place, distance, strength, summary) needs a plan with the full event detail; without it records return the time, position and kind with detail_withheld=true and a placeholder title. MCP server 3.3.0.
An event now says how far it is established. occurrence_status on each signal (GET /api/v1/signals, MCP query_signals) is claimed when the only party stating it happened is the side saying it carried it out, disputed when the side said to have been hit, or an authority, denies it, and reported otherwise; null means not yet assessed, not confirmed. The event thread (GET /api/v1/events/{eventId}/thread, MCP get_event_thread) adds canonical_event.occurrence with who claimed it, who denied it, who has not confirmed it and what was seen (an observation such as smoke or fire says nothing about the cause), each with its source report. The titles and summaries of claimed and disputed events are written as a claim. Casualty counts are stricter: a figure of 100 or more that only one report gives, on an event with three or more reports, is not shown as the event's toll, and a single figure for killed-or-wounded is not shown as deaths; both are listed in canonical_event.casualties.not_counted with the report they came from. reporting.distinct_texts counts outlets carrying the same wire copy once (it is not a count of independent confirmations). Named targets that are different wordings of one site are shown as one. The status is returned on every plan; who said what follows the full event detail, and the source reports follow the evidence. The Python SDK (2.4.0) adds Signal.occurrence_status and reporting.distinct_texts. The MCP tool list is unchanged.
Watch notifications say more and arrive less often. In GET /api/v1/notifications, a related_event notification now carries the linked event's summary and, in why, a sentence on how the two events are linked (for a shared facility: whether each event names it as its location or as its target). Fewer relations become notifications: a shared facility only when reports of both events name it, a shared place only when both events are located there, and a recorded campaign. The relations recorded for an event (GET /api/v1/events/{eventId}/related, MCP get_related_events) are unchanged, and so is the MCP list_notifications digest. By email, newly related events are sent at most once a day in one message covering all your watches; a change to a watched event itself is still sent in the same hour.
An event reported in a strait or a sea is now linked to it in the location registry when a report gives that strait or sea as where it happened. Such reports were read for the finer place name only, so an event inside the Strait of Hormuz could be left without the link. Existing events were relinked. This shows in an entity's event history (GET /api/v1/entities/{entityId}, MCP get_entity) and in the relations of an event.
Watch notifications can be posted to Slack or Discord. Connect one channel per account in the app (account settings → Email & Slack → Add to Slack / Add to Discord; the channel is picked on Slack's or Discord's own consent screen), then turn it on per watch. Each hourly batch of changes for a watch arrives as one message, with the same content and the same plan withholding as the email. Free on every plan. Over the API: notify_chat on PATCH /api/v1/watches/{watchId} and MCP update_watch (server 3.2.0); GET and DELETE /api/v1/notification-channel read and disconnect the channel (the webhook URL is never returned) and POST /api/v1/notification-channel/test sends a test message. The Python SDK (2.3.0) adds client.notifications.channel and watches.update(notify_chat=...).
MCP server 3.1.0 and Python SDK 2.1.0: MCP get_related_events is back — the relations recorded for one event (the same registry facility, the same named place, the same campaign, and reports merged into it), each saying what is shared, 1 token. Asking whether two events are connected is a question asked in a conversation, so it belongs on MCP. GET /api/v1/events/{eventId}/related and client.entities.related_events are unchanged. MCP now serves 22 tools (23 with the weather licence).
Notifications over the API: GET /api/v1/notifications lists every change your watches reported — an event development, a newly related event, an anomaly in a measurement, a new event at a site, a new scene, a fired standing order — newest first with its read state, the same list as the bell in the app. Filter by unread_only, kind or watch_id and page with next_cursor; unread_count is your total unread. A value your plan does not open is marked locked with lock_plan naming the plan that opens it. POST /api/v1/notifications/read marks notifications read by ids or all (optionally for one watch). Both are free. MCP list_notifications (server 3.0.0) lists them without marking anything read; the Python SDK (2.0.0) adds client.notifications with list, iterate and mark_read.
MCP server 3.0.0 (breaking): the MCP server now serves the 21 tools meant for a conversation, and every result is smaller. Chat clients load every tool into context and cut long tool results, so survey_observable_events, create_standing_order, list_standing_orders, list_layer_sets, get_layer_set, list_uploaded_layers, list_monitored_areas, get_monitored_area, create_monitored_area, delete_note, get_related_events, lookup_elevation, analyze_terrain, measure_index_series and detect_ships moved to the REST API and the Python SDK only (nothing was removed from REST or the SDK). Calling one of them over MCP returns code api_only with its REST operation and SDK method. Over MCP, query_signals returns digest rows (20 by default, 50 at most), search_imagery returns scenes without per-band asset URLs or the footprint polygon (10 by default, 25 at most) and query_developments pages 20 by default (50 at most); each list carries full_records — the same query as a REST URL and a Python SDK call, for every field and pages of up to 500.
MCP server 3.0.0 and Python SDK 2.0.0 (breaking): GET /api/v1/signals and MCP query_signals no longer take observable, sensors, collection_levels or escalation_trends (collectionLevels / escalationTrends in MCP). The Map in the app now uses the Watchfloor's filters, so these Map-only filters left the app, and the API follows the app. Passing one is refused with a 400 that says what to do instead: each signal still carries collection.observable, collection.sensor, collection.level and escalation_trend. meta no longer echoes these four or reports drop counts for them. A pagination cursor issued before this change is refused as belonging to a different query; start the listing again without it.
A new area watch (MCP create_watch, POST /api/v1/watches, the Python SDK) is limited to 100,000 km², the same limit as a standing order; a larger box is refused with 400 invalid_input naming the limit (to follow a whole country, watch a site at country scale). Re-adding an area that is already watched is not refused.
GET /api/v1/signals, MCP query_signals and the Python SDK take watch_id: only the events linked to one of your watches (the id from list_watches) — the Watchfloor's "Near my places" for one place. meta reports watch_id, watch_linked_events and dropped_by_watch_count.
Event detail now opens part by part by plan, the same rule in the app, on the public event pages and through the API. With the full event detail you get what happened: the reported facts, the places and facilities named and the value of every change. Each of the rest opens on its own: every report with the one behind each fact and each change, the related events, the collection recommendation with the GEOINT score and imagery status, the market reasoning, sort=geoint and linked_to. plan_lock.section_plans names the plan that opens each withheld part, and meta.filter_clamp.required_plans the plan that opens each dropped filter.
GET /api/v1/signals, MCP query_signals (server 2.1.0) and the Python SDK (1.1.0) take linked_to: only the events that share one stored connector — actor:<name>, place:<place_key> or facility:<entity_id>. It is the Watchfloor's "Filter to these events" on a connector, and it needs a plan that includes it (meta.filter_clamp says when it was not applied). meta echoes linked_to and counts dropped_by_linked_to_count.
Inputs now match the app's screens, in the screens' shape. GET /api/v1/signals and MCP query_signals take the Watchfloor's filters — a date range (start_date / end_date) or a time window (recency 15m / 1h / 24h, default 24h), q, categories, stages, min_severity_band (4 / 6 / 9), min_publishers (2 / 3 / 5), markets and placement (all / map / list) — and the map's: observable (any / yes / no), sensors, collection_levels and escalation_trends, where an event not yet assessed passes. sort is latest (default), oldest or geoint. date, days, reported_since, plottable_only, unplottable_only, observable_only, escalating, min_severity, min_geoint and created_since are refused with 400 naming the replacement. On Free, the Watchfloor filters beyond category (q, stages, min_severity_band, min_publishers, markets, placement) are not applied and meta.filter_clamp says so. The map's layer filters now run on the server under the same rule. response_format is removed from every MCP tool: every tool returns its full result. query_developments and search_imagery take a date range (start_date / end_date; MCP search_imagery: startDate / endDate) instead of date and days. create_standing_order (POST /api/v1/standing-orders) takes only bbox, name and notify_email and checks weekly, like the app's "Watch this area"; question, cadence, categories, min_geoint_score and min_new_events return 400. update_watch (PATCH /api/v1/watches/{watchId}) no longer renames a watch. The standing-order create response no longer carries projected_monthly_tokens_typical / _max: an order made this way sends a digest of the new events without running a model and is never charged. Added what only the app offered: create_monitored_area (POST /api/v1/monitoring) takes satellite, the sensor the app's monitoring form picks for a metric (for example ship detection on NISAR), and detect_ships (POST /api/v1/ships) accepts a NISAR L-band scene with the plan's NISAR access. MCP server 2.0.0.
Removed on every plan, because each had no counterpart in the app (the API, MCP server and SDK now offer only what an app screen, including the Delta Agent chat, offers): query_stats and query_hotspots (GET /api/v1/signals/stats and /signals/hotspots); get_decision_package (GET /api/v1/watches/{watchId}/decision-package); POST /api/v1/watches/{watchId}/readouts; delete_standing_order (DELETE and POST /api/v1/standing-orders/{orderId}) — a standing order is now paused, resumed or removed through the watch it joined, with update_watch / delete_watch (PATCH / DELETE /api/v1/watches/{watchId}); the MCP prompts daily-situation-briefing, assess-top-signal, aoi-watch and market-exposure-check (the server no longer advertises prompts); and the imagery://collections resource. The claim ledger is retired: query_claims and GET /api/v1/claims are removed, and get_entity (GET /api/v1/entities/{entityId}) no longer returns claim_count. The evidence badges inside a single Delta Agent answer are unchanged. The Python SDK drops the matching methods in 1.0.0. MCP server 2.0.0.
Event detail follows the key owner's plan, the same rule as the app and the public event pages. On a plan without the full event detail (Free), signals, a signal by id, the event thread and related events withhold the reported facts beyond the casualty counts, the collection reasoning and imagery status, and the market reasoning, and plan_lock names what was withheld — a null there means not shown, not unknown. MCP server 1.37.0.
Time windows are bounded by the key owner's plan: without real-time a window ends yesterday, without the date range it ends on the latest readable day, and it never starts before the plan's history floor. meta.window_clamp says what was narrowed, so a shorter window is never silent. MCP server 1.37.0.
GET /api/v1/signals (and the Python SDK's signals.list) take q (free-text search, the same as the Watchfloor), reported_since, min_publishers and unplottable_only. Follow meta.next_cursor until it is null to read every matching signal; meta.total_count is exact and each page is charged.
GET /api/v1/brief and MCP get_world_brief take period: daily (default), weekly or monthly. Weekly and monthly are free of tokens and opened by the key owner's plan — the same entitlement as the app's Reports — and return 403 otherwise; date is the last day of the period, and available_periods lists the published ones. GET /api/v1/brief now returns the same fields as the MCP tool (status, freshness, quality, changes_since_previous_brief for daily). The category and location counts in stats now cover every event in the period rather than the highest-severity candidates. Python SDK: brief.get(period=...).
Per-site condition. Signals carry target_effects — for each named target a report describes individually, its condition (name, status, the report's note, and disputed when another report states a different condition). target_status stays the one event-level condition. GET /api/v1/events/{eventId}/thread and MCP get_event_thread return canonical_event.targets with each site's condition and the report that stated it; query_developments adds the axis target_effect (value "<site>: <status>"). A site with no condition has no stated condition, which is not the same as undamaged. Python SDK: Signal.target_effects.
GET /api/v1/events/{eventId}/related and MCP get_related_events now cost 1 token (was 3), the same as an entity lookup. Since they were rebuilt on the relations recorded for an event, a call is a single read of that event. MCP server 1.36.0.
The current event record starts on 2026-09-23. The window parameters of query_signals, query_stats, query_hotspots, query_developments, rank_imaging_priority and survey_observable_events (and their REST operations) now say so: a window before that date returns no events because none were recorded, not because none happened.
Watches read the current event record only. GET /api/v1/watches/{id} and MCP get_watch now attach the event thread to an event watch (it was missing for every watch created since 2026-09-24), and the decision package (schema_version 2.0) reads the event, its claims and its imagery state from the current record: target.event_id is the event UUID and current_state carries stage and stage_reason instead of verification_status. The previous record's event block on a watch is removed; the 16 watches on that record were closed on 2026-09-24 and no longer appear in the list.
GET /api/v1/events/{eventId}/related, MCP get_related_events and the Python SDK entities.related_events() now return only the relations recorded for the event, and take its UUID. Each related event says what it shares in shares: the same registry facility, the same place resolved to a town or finer, or a relation stored when the events were processed (same_campaign); facilities and places give each connector's total beside how many are listed, and merged_in lists reports merged into the event. max_hop, include_hypotheses, context, network, nearby_facilities, assessment, insights, hypotheses and meta are removed: they were derived from the previous corpus on every call and have no stored source in the current one. The charge is a flat 3 tokens. GET /api/v1/entities/{entityId} and MCP get_entity return the most recent linked events with a UUID, stage and link_kind (named_location / named_target / proximity) and add events_24h; link_basis_counts and observability are removed.
refine_location is retired on every surface: the MCP tool, POST /api/v1/signals/{id}/refine-location, the Python SDK method signals.refine_location, and the Delta Agent tool. It wrote into the previous event corpus, and in the current one the next refold would overwrite a paid refinement, so it stays off until it can be stored where the refold respects it. An event now says how precisely its place is established and why it is not finer (stage, stage_reason). MCP server 1.35.0 (40 tools).
Every signal now carries the NATO grading (Admiralty code) of its best report: reporting.source_reliability_best (A–F), reporting.credibility_best (1 = confirmed by other sources … 6 = cannot be judged) and reporting.graded_members. The triage model grades each report from its text; the corpus folds the best grade per event. Breadth (distinct_hosts), grading and the stage ladder are separate axes, and none of them is independence. Returned by GET /api/v1/signals, /signals/{id}, MCP query_signals and get_event_thread, and the Python SDK Reporting model.
The event corpus behind the API changed. GET /api/v1/signals and MCP query_signals now read the new signal corpus: id is a UUID (a numeric id from the previous corpus no longer resolves, and the error says so), each event reports how precisely its place is established (stage: reported = country or province only, or not placeable → localized = town or city → pinpointed = street block or facility) with stage_reason for why it is not more precise, and whether a satellite could see it (collection.observable, collection.observable_reason — the effect is large enough to show from orbit and the place is fine enough to frame it; null means not assessed), and reporting.member_count / reporting.distinct_hosts replace article_count / independent_source_count (the outlet count never collapsed syndication, so it is breadth, not independence). Removed because nothing measures them any more: goldstein_scale, avg_tone, num_mentions, tags, event_type, source_url; the filters taskable_only, collection_ready_only, observability, observability_status, open_data and min_information_gain are rejected with the name of their replacement (observable_only, sensors, min_geoint, plottable_only). New filter observable_only keeps events a satellite could see. sort=geoint ranks events a satellite could see first, then geoint_score, then stage, so an event whose observability has not been assessed, or whose place is too coarse to frame, cannot lead a collection ranking. MCP server 1.34.0.
Every surface that names an event takes the new UUID: query_developments / get_event_thread, assess_signal (POST /api/v1/assess), plan_event_imagery (GET /api/v1/collection/plan), rank_imaging_priority, survey_observable_events, refine_location, query_claims (event_id) and the findings of ask_analyst. An id that was folded into another event resolves to that event and says so (merged_from_request). assess_signal reports the corpus record (distinct_hosts, member_count, the report grading, stage, authenticity_concern) in context.signal_verification instead of a derived verification_status; a location the corpus resolved only to a country or province is refused before any charge (needs_repair, with the stage reason) rather than planned around a centroid. query_stats and query_hotspots count the same events query_signals returns, so totals agree for the same query.
GET /api/v1/status and the MCP status://current resource now report the freshness of the new corpus: data_current_through is the newest slot the ingestion worker processed and last_enrichment is when an event state was last folded; a cycle that ran but failed a stage reports enrichment as delayed rather than operational. Field names are unchanged.
Two measurements that already existed inside the product are now callable. measure_index_series (POST /api/v1/index-series) measures a spectral index over a polygon scene by scene back through the Sentinel-2 archive — NDVI, NBR, NDWI and the rest — metered per scene actually measured, with estimate_only returning the scene count, the true date span and the cost for free first. Three limits are in the response rather than in a footnote: the archive begins 2015-06-27 so an earlier start is clamped and says so, at most 24 scenes are measured per call so a longer period comes back as a sample with the remainder in skipped, and trend compares the first and last measured scene only, so it carries no rate and no confidence. detect_ships (POST /api/v1/ships) counts vessel-like targets in one Sentinel-1 scene using CFAR detection; read caveats before quoting count, because an unavailable land mask, the coastal exclusion buffer and partial scene coverage each change what the number means. A scene the detector refuses is not charged. Both call the same code as the in-app feature. MCP server 1.11.0, 24 tools.
Terrain over the API and MCP. lookup_elevation (GET/POST /api/v1/elevation) measures height from the Copernicus DEM GLO-30 at a point, over a bounding box, or inside a drawn polygon — min, max, mean, median, p10, p90 and relief. analyze_terrain (GET /api/v1/terrain) computes from the terrain rather than reading heights out of it: the share of an area lost to SAR layover and shadow for a given incidence angle and look direction plus the mean local incidence angle, and the ground profile between two points with a line-of-sight verdict including Earth curvature. Both are free of token charges. Three properties travel with every answer because they change what it means: it is a surface model (buildings and canopy included), a large area is read below the 30 m posting so extremes are smoothed inward, and no coverage over open water is absence rather than 0 m.
create_standing_order reported a cost ceiling that was not a ceiling. projected_monthly_tokens_max was computed from the OBSERVED MEDIAN cost per Analyst run, not the per-question cap, so it bounded how often an order could fire but not what a firing could cost — at daily cadence it advertised 1,370 tokens/month where the true worst case is 3,744. The field is now computed from the per-question cap and means what its name and documentation always said. A new additive field, projected_monthly_tokens_typical, carries the median-based forecast so the useful number is still available. If you sized a plan against the old value, re-check it: the ceiling did not change, only the number we published for it.
Delta Monitor over the API and MCP: create_monitored_area puts a place under continuous satellite measurement (pick a bounding box and a metric — the sensor follows from the metric, so ship counts use SAR and survive cloud and darkness), list_monitored_areas returns each area with its latest value, the change since the previous measurement and whether it was flagged anomalous, and get_monitored_area returns the full measurement time series. Creating and listing are free — you are metered only when new imagery is actually measured. REST equivalents: /api/v1/monitoring and /api/v1/monitoring/{areaId}. MCP server 1.8.0, 20 tools.
query_claims returned nothing for API and MCP callers. The claim ledger was only written from the in-app path, so claims asserted by an ask_analyst run started over the API were never recorded. Analyst runs now persist claims wherever they were started. Ledgers populate from this date forward; earlier API runs cannot be backfilled.
verification_status can now return disputed. The value was always in the published enum but was previously unreachable: an analyst authenticity review that finds the supporting media fabricated now demotes the signal, and a write-time notice that occurrence is unconfirmed caps it at corroborated instead of promoting it. New additive fields: intelligence.verification_review {flags, reviewed_at, source} and confirmation_basis (independent_reporting / corroborated_reporting / single_report / analyst_review / imagery / none). If you branch on verification_status, add a case for disputed.
ask_analyst and get_analyst_job accept an optional response_format of full or compact. compact omits the prose brief and returns only the structured result, materially reducing the context an agent spends re-fetching a finished run. Default is full, so existing callers are unaffected. snake_case argument aliases are now normalised rather than rejected, and unknown fields come back in an additive warnings array instead of being dropped silently; a missing required argument now lists the keys actually received.
get_analyst_job (MCP) and GET /api/v1/analyst/{jobId} (REST) now return an identical key set. REST gained idempotency_key, question, and deliverable_gaps, and the documented 200 response now includes structured, result_quality, freshness, result_schema_version, and chargeable.
predict_satellite_passes now states plainly that every pass it returns is a geometric access opportunity (geometry_only: true, acquisition_plan_verified: false) — it means the satellite could see the location, never that a collection was scheduled. Sentinel and Landsat passes are described as routinely collected and therefore near-certain rather than as acquisitions you are guaranteed to receive. With no start_date, the window begins now.
survey_observable_events documents that its population is not gated by tasking readiness, so its totals legitimately exceed rank_imaging_priority and count a different unit from query_signals (which collapses to event clusters). A new population_detail field explains the denominator; use each event’s collection_ready flag to narrow to what is actually taskable.
query_claims (free): an audit trail of what Delta told you. Every claim an Analyst run asserted on your key, with its evidence class (CONFIRMED / REPORTED / PARTY_CLAIM / ASSESSMENT), how many independent source families backed it, the publishers, and whether a later answer restated it with stronger or weaker evidence. Filters: restated_only, downgraded_only. Scoped to your own key.
Standing orders: create_standing_order saves a question plus a bounding box and re-answers it on a schedule, telling you only when the answer actually changed; list_standing_orders shows cadence, watched area, last check, last fire, and how many consecutive checks found nothing; delete_standing_order deletes, or pauses with active=false. Creating and listing are free — a check that finds nothing invokes no model and costs nothing, and only a firing check is metered. A bounding box is required, and cadence and order count are limited by plan (the error states which limit was hit). create_standing_order returns projected_monthly_tokens_max so the ceiling is visible before you commit.
Collection planning over the API and MCP: predict_satellite_passes (2 tokens) for when a place can next be imaged and by which satellite, separating free systematic Sentinel/Landsat coverage from taskable commercial windows; rank_imaging_priority (1 token) for where observation is most worthwhile and what class of satellite it needs; survey_observable_events (1 token) for which events a given sensor can actually resolve; and plan_event_imagery (4 tokens) for the deterministic plan for one event, which searches SAR and optical exactly once each so the all-weather look cannot be missed.
ask_analyst accepts an optional mode of fast or deep. Default remains fast, whose advertised 5–123 token band is unchanged. deep raises the per-question ceiling to 415 tokens for questions needing more retrieval and reasoning; charging stays metered by actual consumption, so the ceiling is a cap and not a price.
Data freshness: new GET /api/v1/status (free) and MCP status://current resource report how current the data is (ingestion / enrichment frontier), the Daily World Brief status, and an Operational / Delayed / Degraded roll-up.
Schema clarity: severity_score and geoint_score are documented with their 0–10 range; escalation_trend now publishes its enum (escalating, de-escalating, stable, new); the /signals parameters observability, open_data, min_information_gain, updated_since, and created_since are documented; sample responses were corrected to include the intelligence block. The machine-readable spec at /api/v1/openapi.json is the source of truth.
Signal filters (observability, min_information_gain, min_severity, markets, escalating) now apply across the full result window before ranking and pagination — a matching event deeper in the feed is no longer dropped, so filtered queries stop returning an empty result when matches exist. REST and MCP behave identically.
The Daily World Brief now passes a deterministic quality gate before publishing; a truncated or structurally-incomplete brief is held back and the previous good brief keeps serving.
Plan access clarified: the REST API, the MCP server, and the AI tools (assess_signal / ask_analyst) are available on every plan, including Free — the only gate is your token balance. get_world_brief and get_usage are free.
MCP: serverInfo.icons[].sizes is now an array per the MCP spec (SEP-973), so strict clients no longer fail to initialize. MCP surface version is 1.3.1.
See the API & MCP reference, the methodology & AI limitations, and MCP setup.