2026-08-22
Changed — /api/v2/events/summary and /api/v2/stories/summary now reject a query parameter they do not declare, with 400 UNKNOWN_PARAM and a suggested spelling, exactly as their list twins have. Both endpoints published a strict contract that nothing enforced: `?countries=NGA` — one character off `country` — returned HTTP 200 and the WORLD's 57,806 events where Nigeria's figure was 2,955, while /api/v2/events answered 400 for the identical typo. `applied_filters.ignored` did report it, but only to a caller who reads that field.
Changing for integrators — five parameters the two summaries accepted and never read now return 400 UNSUPPORTED_PARAM naming the list endpoint instead: `sort`, `cursor`, `offset`, `include_images` and `include_entity_images`. A summary returns buckets, so there was nothing for them to order, page or illustrate; being on the allowlist meant they were echoed back as APPLIED, so paging a summary with `offset` returned page one every time under a response that agreed the offset had been used. `limit` still bounds the number of buckets. In the other direction, `languages`/`language` were applied by both summaries all along and are now declared, documented and generated like every other filter.
Changed — an entity filter whose material attribution is not yet built for the requested window now returns broad story coverage and SAYS SO, rather than failing. `applied_filters` carries `entity_match: "coverage"`, `coverage_fallback_applied: true` and a sentence explaining what the rows are. Sending `entity_match=material` explicitly still returns 503 ENTITY_ATTRIBUTION_UNAVAILABLE — if you asked for material by name you get a straight answer, not a substitute.
Fixed — the same unavailability could also produce an empty HTTP 200. The availability check sat behind entity resolution, and entity resolution is scoped to the requested window, so an entity with no coverage in that window skipped the check entirely and received zero rows next to our own note saying the filters were understood and nothing matched. Whether a capability is available never depended on the entity; it now cannot depend on how much news that entity made.
Fixed — /api/v2/events/summary returned an untyped 500 INTERNAL_ERROR where /api/v2/events returned 503 ENTITY_ATTRIBUTION_UNAVAILABLE with `details.retryable` for the same condition. A retry policy written against one surface behaved wrongly against the other. Every v2 endpoint now answers that condition identically.
Fixed — `include_total=1` produced no `pagination.estimated_total`, was echoed back as though it had been applied, and never appeared in `applied_filters.ignored`; `include_total=True` was accepted by the contract and then silently dropped. Booleans are `true` or `false` in any casing, and anything else is now a 400 INVALID_BOOLEAN that says so. If you were sending `1`, send `true`.
Fixed — the MCP `summarize_events` and `summarize_stories` tools reported the per-event AVERAGE under the field name `article_count`, which is the total everywhere else. For 2026-07-29 an agent read 2.589 where the REST bucket says 321; over a 30-day window, 89 articles against 8,399. Both numbers are now published, under the names REST uses. Three neighbours went with it: story summary buckets reported no `count` at all, the four CAMEO+ metrics were dropped from every digest, and a nested aggregate was emitted where a number was promised.
Added — a published API stability and deprecation policy, at docs.gdeltcloud.com/reference/stability. At least 30 days' notice before a breaking change or an endpoint removal; what changes without notice, and why data corrections are on that list; what deprecated, retired and removed each mean and how to tell them apart from a response. Its inventories are generated from the same contract the API enforces, so the page cannot outlive its subject.
Added — the changelog is now an RSS feed at /changelog/feed.xml, linked from this page's head. It was previously the only channel for a breaking change and the only way to read it was to remember to visit it.
Fixed — the parameter reference miscounted which endpoints share a parameter, because a name accepted on one endpoint and rejected on another was recorded once and judged by whichever it met first. `as_of` was missing from the shared table entirely and several geography parameters were overcounted.