Skip to main content

Versioning & deprecation

The Evinor API is versioned in the URL path. The current version is v1, and every endpoint lives under /v1 (for example, GET /v1/sensors).

Additive-only within a version​

note

/v1 is currently in preview. The guarantees below bind from general availability; while the API is in preview we may make corrective breaking changes — such as settling on one name for a concept that shipped under two — and every such change is announced in the changelog below.

Within /v1, changes are additive and backward-compatible. That means we may, without a new version:

  • add new endpoints;
  • add new optional request parameters (existing requests keep working unchanged);
  • add new fields to response bodies.

Within /v1 we will not:

  • remove or rename an existing response field;
  • change the type or meaning of an existing field;
  • make a previously optional request parameter required;
  • remove an endpoint.

A change that would break any of those guarantees ships under a new version path (for example, a future /v2), never as an in-place change to /v1.

Build a tolerant client​

Because new fields can appear at any time, write your integration to be forward-compatible:

  • Ignore unknown fields rather than rejecting a response that contains them.
  • Don't depend on field ordering in JSON objects.
  • Branch on documented type URIs and status codes for errors, not on human-readable text (see Errors).

Following these rules means additive changes never break your integration.

Deprecation policy​

When we eventually deprecate part of /v1 in favor of a newer version, we commit to:

  • a minimum 12-month window between announcing a deprecation and removing the deprecated behavior;
  • advance notice, so you have time to migrate.

Once deprecation signaling is in place, deprecated endpoints will advertise it with standard HTTP response headers:

  • Deprecation — indicates the endpoint is deprecated.
  • Sunset — the date after which the endpoint may stop working.
note

These deprecation headers describe our forward-looking policy. The current /v1 API is not deprecating anything and does not emit Deprecation or Sunset headers today — they will appear only if and when a deprecation begins.

Changelog​

Notable additions, any deprecation announcements, and any preview-window corrective changes are published here on the Evinor developer portal. Check back before relying on newly added fields, and watch for deprecation notices if you depend on behavior slated to change.

2026-10-25 — event_date on events and beat entries; eventDate on webhooks; occurredAt deprecated​

Additive:

  • Events from POST /v1/events/search (and the search_events / search_events_continue MCP tools) and each beat entry's event gain event_date: { value, source, precision } or null — when the event happened, whether it was STATED or ESTIMATED, and whether it is precise to the DAY or the MONTH. happened_at is unchanged. See The event date.
  • Webhook deliveries gain an optional payload.eventDate with the same shape, derived from the report that crossed the sensor's threshold. See When the event happened.
  • Slack deliveries now show the event date as "Occurred" (with est. for an estimate), instead of the match time.

Deprecated:

  • payload.occurredAt on webhook deliveries. It has always been the match time (the same instant as payload.details.matchedAt), not when the event happened. It is still sent, with the same value.

2026-10-17 — two new entity type values: DISEASE and VULNERABILITY​

Additive:

  • An entity's type can now be DISEASE (a named disease, disorder or syndrome, or its pathogen, such as "measles") or VULNERABILITY (a specific named security flaw, such as a CVE or GHSA id or "Log4Shell"). The new values can appear on involved_entities[].type in POST /v1/events/search (and the search_events / search_events_continue MCP tools) and on type in GET /v1/entities/search.
  • type is a free string in the public schema (and may be null), so this is not a breaking change. A client that treats type as a closed enum must accept the two new values.

2026-09-26 — report-source filter on sensors and event search; triggeringReport and user provenance on webhooks​

Additive:

  • Sensor filters (/v1/sensors) and POST /v1/events/search accept report_source_kind (ANY, ARTICLES_ONLY, USER_REPORTS_ONLY, REPRESENTED_ONLY), represented_entity_ids, and represented_entity_list_ids. Sensor responses always carry all three (ANY / [] / [] by default). See The sensor filter.
  • On PATCH /v1/sensors/{id} with a filter, missing report-source keys keep their stored values, while missing legacy filter keys still reset to their defaults.
  • Webhook deliveries gain an optional payload.details.triggeringReport and, when a user report fired the sensor, one provenance entry with sourceKind: "user". A receiver that validates provenance[].sourceKind as a closed enum must accept "user". See User provenance.

2026-09-14 — event search ordered and windowed by first report; last_report_date restored (preview correction)​

This supersedes the ordering note in the 2026-09-13 entry below. Events returned by POST /v1/events/search (and the search_events / search_events_continue MCP tools) change as follows:

WasNow
Results ordered by most recent matching coverageResults ordered by first_report_date, newest first (ties broken by id)
lookback_days included any event with a matching report inside the windowlookback_days selects events first reported inside the window
first_report_date — an ISO 8601 UTC timestamp or nullfirst_report_date — an ISO 8601 UTC timestamp, never null
No last_report_datelast_report_date — when the event was most recently reported, an ISO 8601 UTC timestamp, never null
matched_report_count / distinct_outlet_count could pick up a late report on page NBoth count only the reports received up to the time of the search, on every page

last_report_date is back with a different meaning from the field removed on 2026-09-13: it is now the publish time of the event's latest report, whether or not that report matched your filters, and it is not the sort key. Both dates describe the event and can change between pages of the same search; see Ordering events in time.

Two consequences to check in your client:

  • A short lookback_days no longer returns an older event just because a recent recap article mentioned it, so total_count for the same filter may be lower.
  • A next_cursor issued before this change is not rejected: continuing with it restarts the search at page one (not re-charged). Search executions are short-lived, so this only affects a search that was being paged across the update — de-duplicate by id if you page through one.

A client that treated first_report_date as nullable keeps working.

2026-09-13 — last_report_date replaced by first_report_date on event search (preview correction)​

Superseded on 2026-09-14: results are now ordered by first_report_date, first_report_date is never null, and last_report_date is back with a new meaning. See the entry above.

Events returned by POST /v1/events/search (and the search_events / search_events_continue MCP tools) no longer carry last_report_date. It has been replaced by first_report_date:

WasNow
last_report_date — the most recent report matching the search, a non-null timestampfirst_report_date — when the event was first reported, an ISO 8601 UTC timestamp or null

last_report_date could not be used to order events: one article covering several events at once gave all of them the same value, however far apart the events really were. first_report_date describes the event itself — it doesn't change with lookback_days or filters — and is the field to sort by when you need events in chronological order. Note that it is nullable. See Ordering events in time.

The order in which results are returned is unchanged. A client that still reads last_report_date will find the key absent.

2026-08-14 — sensor filter fields renamed (preview correction)​

/v1/sensors and /v1/events/search had shipped two different names for the same two concepts. The sensor surface now uses the same spelling as the search surface, so there is one name per concept across the whole API:

ConceptWas (on /v1/sensors)Now
Event typeincident_template_idevent_type_id
Involved entitiesinvolved_entity_canonical_idsinvolved_entity_ids

This affects the filter object on GET /v1/sensors, GET /v1/sensors/{id}, POST /v1/sensors, and PATCH /v1/sensors/{id}. The retired names are no longer accepted — a request sending one is rejected with a validation-failed problem naming the offending field, rather than silently ignoring it.