> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gdeltcloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API stability and deprecation

> What we commit to before a breaking change, what deprecated/retired/removed each mean, and how to be told.

**We give at least 30 days' notice before a breaking change to a published endpoint, and before removing one.** A renamed parameter keeps answering under its old spelling for at least 30 days after the rename is announced. These are minimums: a change with a wide blast radius gets longer.

A change is **breaking** if a request that works today stops working, or if a field a caller
is already reading changes its meaning, its type, or disappears.

## What changes without notice

Stated plainly, because a policy that implies nothing ever moves is one we would break in a
week — and because two of these are customer protections rather than exemptions from one.

* Adding a new endpoint, a new optional parameter, or a new field to a response body. Parse responses permissively — an unrecognised field is not an error and will not be announced.
* Widening what an existing parameter accepts, or adding a value to an OPEN vocabulary (source registries, form types, language codes). A closed enum gaining a value is announced.
* Correcting data. A score, a classification or a count that was wrong is fixed as soon as we know, and the changelog says so — waiting 30 days to stop serving a wrong number would be the opposite of a customer protection.
* Fixing a defect where the current behaviour is itself the hazard: a 200 hiding a wrong answer, a filter that silently does not apply, or a value we publish and then refuse.

**Parse responses permissively.** A new field is not a breaking change and will keep
appearing; a client that rejects unknown fields has opted into breakage we do not announce.

## Deprecated, retired, removed

Three different states, routinely read as synonyms. Only one of them stops working.

| State          | What it means                                                                                                                                                                                                                                                                                                                                                             | How you can tell                                                                                                                                                              |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Deprecated** | Still fully supported and still applied. It has a replacement we would rather you used, and it is no longer offered to new integrations in the docs, the OpenAPI spec or the MCP schema.                                                                                                                                                                                  | The parameter carries `deprecated` in the OpenAPI spec, with the date and the replacement.                                                                                    |
| **Retired**    | Still accepted — it will never 400 — but it no longer affects the result. This is how a filter is withdrawn without breaking a caller who is still sending it: the response NAMES it as retired rather than letting it look applied, so a caller who reads the response can tell what happened, and a caller who does not gets MORE data than they asked for, never less. | `applied_filters.retired[&lt;name>]`, carrying the date it stopped applying and what to use instead.                                                                          |
| **Removed**    | The path is gone and will not return. It answers `410 Gone` — not 404 — because "intentionally gone" is something caches and retry policies act on, while 404 means "no idea, try later" and the rational response to that is to retry forever.                                                                                                                           | `410` with `code: ENDPOINT_REMOVED`, the successor path in `details.replacement` and in an RFC 8594 `Link: &lt;…>; rel="successor-version"` header, plus `Deprecation: true`. |

## How you are told

| Channel                       | Where                                                                                | What it carries                                                                                                                                                                    |
| ----------------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Changelog                     | [gdeltcloud.com/changelog](https://gdeltcloud.com/changelog)                         | Every product-meaningful change, newest first. The system of record for what changed and when.                                                                                     |
| RSS feed                      | [gdeltcloud.com/changelog/feed.xml](https://gdeltcloud.com/changelog/feed.xml)       | The same entries as a feed, so a breaking change can reach a reader, a Slack channel or a CI job without anyone remembering to check a web page.                                   |
| Response headers              | [docs.gdeltcloud.com/reference/errors](https://docs.gdeltcloud.com/reference/errors) | A removed path answers 410 with `Deprecation: true` and a successor `Link`. A client that reads either header learns the migration without parsing a body.                         |
| The machine-readable contract | [gdeltcloud.com/openapi.json](https://gdeltcloud.com/openapi.json)                   | Generated from the executable descriptors the server validates against, so it cannot describe a behaviour the API does not have. Diff it between releases to see the surface move. |

## Which endpoints are governed by an executable contract

17 of 90 published endpoints are **descriptor-backed**: the server imports the same descriptor this documentation, the OpenAPI spec and the MCP tool schema are generated from, and validates your request against it at request time. Their published contract cannot drift from their behaviour, and they answer `400 UNKNOWN_PARAM` — with a suggested spelling — for a parameter they do not declare.

The remaining endpoints are live and supported; their published shape is hand-maintained, and a parameter they do not recognise is reported in `applied_filters.ignored` rather than refused. **Check `applied_filters.ignored` on every response.** It is the difference between a filter that narrowed your result and one that was dropped.

`GET /api/v2/meta/endpoints` reports the current split, per endpoint, in its `coverage` key.

## Currently deprecated parameters

Still supported and still applied. Migrate at your convenience; you will get the notice above
before any of them stops working.

| Parameter      | Deprecated | Use instead | On                                                                                       |
| -------------- | ---------- | ----------- | ---------------------------------------------------------------------------------------- |
| `domain`       | 2026-05    | `category`  | `/api/v2/events`, `/api/v2/stories`, `/api/v2/events/summary`, `/api/v2/stories/summary` |
| `event_family` | 2026-05    | `category`  | `/api/v2/events`, `/api/v2/stories`, `/api/v2/events/summary`                            |

## Retired parameters

Accepted, never rejected, and no longer affecting results. Each is named in
`applied_filters.retired` on any response where you send it, with this sentence.

| Parameter                      | Retired    | What to do                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `canonical_cluster_date_end`   | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It bounded the linked STORY's cluster date — a third date vocabulary on an endpoint that already has two (`date_start`/`date_end` for when the event happened, `observed_start`/`observed_end` for when we coded it), and the only one named after an internal join rather than after anything a reader of the data would recognise. It also forced the request off the daily snapshots: measured 6,487 ms live against 1,144 ms settled on the identical window, which made it the single largest latency cost on this endpoint. Use `date_start`/`date_end` to bound when events happened, or `observed_start`/`observed_end` to bound when they were coded. Each linked story's own date is on the card under `story_refs`. |
| `canonical_cluster_date_start` | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It bounded the linked STORY's cluster date — a third date vocabulary on an endpoint that already has two (`date_start`/`date_end` for when the event happened, `observed_start`/`observed_end` for when we coded it), and the only one named after an internal join rather than after anything a reader of the data would recognise. It also forced the request off the daily snapshots: measured 6,487 ms live against 1,144 ms settled on the identical window, which made it the single largest latency cost on this endpoint. Use `date_start`/`date_end` to bound when events happened, or `observed_start`/`observed_end` to bound when they were coded. Each linked story's own date is on the card under `story_refs`. |
| `canonicalClusterDateEnd`      | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It bounded the linked STORY's cluster date — a third date vocabulary on an endpoint that already has two (`date_start`/`date_end` for when the event happened, `observed_start`/`observed_end` for when we coded it), and the only one named after an internal join rather than after anything a reader of the data would recognise. It also forced the request off the daily snapshots: measured 6,487 ms live against 1,144 ms settled on the identical window, which made it the single largest latency cost on this endpoint. Use `date_start`/`date_end` to bound when events happened, or `observed_start`/`observed_end` to bound when they were coded. Each linked story's own date is on the card under `story_refs`. |
| `canonicalClusterDateStart`    | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It bounded the linked STORY's cluster date — a third date vocabulary on an endpoint that already has two (`date_start`/`date_end` for when the event happened, `observed_start`/`observed_end` for when we coded it), and the only one named after an internal join rather than after anything a reader of the data would recognise. It also forced the request off the daily snapshots: measured 6,487 ms live against 1,144 ms settled on the identical window, which made it the single largest latency cost on this endpoint. Use `date_start`/`date_end` to bound when events happened, or `observed_start`/`observed_end` to bound when they were coded. Each linked story's own date is on the card under `story_refs`. |
| `confidence_profile`           | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a preset over INTERNAL story-cluster grades, not a confidence filter: any value other than `loose` required visibility\_tier=primary and story\_family\_grade=strong, which discarded roughly 61% of retrievable Stories — including clusters graded weak at creation that later grew to hundreds of articles, because that grade is stamped once and never revised. Use `confidence_min` for a floor on the coder confidence score.                                                                                                                                                                                                                                                                                    |
| `goldstein_max`                | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `goldstein_min`                | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `goldstein_severity_max`       | 2026-08-15 | Retired 2026-08-15 and no longer affects results. Goldstein severity is not a separate metric — it is the ABSOLUTE VALUE of `goldstein_scale`, which is served on every card, so the same screen is `goldstein_scale_min` / `goldstein_scale_max` (a signed band) or one line of arithmetic on the value you already receive. Filtering on it also forced the request off the daily snapshots, so it was materially slower than the filter it duplicated. The `goldstein_severity` STATISTICS on /api/v2/events/summary are unchanged — an aggregate is not something a caller can compute from a single card, which is exactly why that one stays and this one does not.                                                                                                        |
| `goldstein_severity_min`       | 2026-08-15 | Retired 2026-08-15 and no longer affects results. Goldstein severity is not a separate metric — it is the ABSOLUTE VALUE of `goldstein_scale`, which is served on every card, so the same screen is `goldstein_scale_min` / `goldstein_scale_max` (a signed band) or one line of arithmetic on the value you already receive. Filtering on it also forced the request off the daily snapshots, so it was materially slower than the filter it duplicated. The `goldstein_severity` STATISTICS on /api/v2/events/summary are unchanged — an aggregate is not something a caller can compute from a single card, which is exactly why that one stays and this one does not.                                                                                                        |
| `max_confidence`               | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_geo_precision`            | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_goldstein`                | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_goldstein_scale`          | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_goldstein_severity`       | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_magnitude`                | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_market_sensitivity`       | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_propagation_potential`    | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_significance`             | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `max_systemic_importance`      | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_confidence`               | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of `confidence_min`, kept only for compatibility, and sitting beside `confidence_profile` it made three unrelated things look like one. Use `confidence_min`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `min_geo_precision`            | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_goldstein`                | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_goldstein_scale`          | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_goldstein_severity`       | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_magnitude`                | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_market_sensitivity`       | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_propagation_potential`    | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_significance`             | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |
| `min_systemic_importance`      | 2026-08-15 | Retired 2026-08-15 and no longer affects results. It was a second spelling of the canonical `&lt;metric>_min` / `&lt;metric>_max` filter, which is unchanged and still applied — so if you were sending this, switch the spelling and your results are identical. Nine metrics each accepted two spellings per bound (plus four short `goldstein` forms), which meant two names to learn per filter, two names in the docs, and a precedence rule for the case where a caller sent both. Across 90 days every alias spelling put together carried about two successful calls, so the surface cost was permanent and the usage was not.                                                                                                                                           |

## Removed paths

These answer `410 Gone`. Each names its own successor in the response body and in a
`Link: <…>; rel="successor-version"` header, so you do not need this page to migrate — call
the path and read the answer.

* `/api/media-events`
* `/api/public/entity-geg`
* `/api/public/entity-geg/baseball-card`
* `/api/public/entity-geg/source-mix`
* `/api/public/entity-geg/theme-abnormality`
* `/api/public/media-events`
* `/api/public/media-events/{cluster_id}`
* `/api/public/media-events/{cluster_id}/conflict`
* `/api/public/media-events/{cluster_id}/events`
* `/api/public/media-events/{cluster_id}/meta`
* `/api/v1/cameoplus-events`
* `/api/v1/conflict-events`
* `/api/v1/conflict-events/summary`
* `/api/v1/entity-geg`
* `/api/v1/media-events`
* `/api/v2/markets`

## If a change breaks you

Email [support@gdeltcloud.com](mailto:support@gdeltcloud.com) with the request that changed
behaviour. A breaking change we shipped without the notice above is our defect, not your
migration.
