GET /v1/events
Returns events, together with any retractions in the same window.
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.docsignal.app/v1/events?domains=linear.app,vercel.com&observed_since=2026-07-01"
Parameters
| Parameter | Type | Meaning |
|---|---|---|
domains | comma-separated | Companies to include, by domain. Defaults to every company your token allows. |
observed_since | YYYY-MM-DD | Only events detected on or after this date. |
observed_until | YYYY-MM-DD | Only events detected on or before this date. |
shipped_since | YYYY-MM-DD | Only events the vendor shipped on or after this date. |
shipped_until | YYYY-MM-DD | Only events the vendor shipped on or before this date. |
origin | observed, backfilled, all | Whether to include history reconstructed from archives. Defaults to all. |
limit | 1–1000 | Page size. Defaults to 100. |
offset | integer | Rows to skip. Defaults to 0. |
If you supply no date window at all, observed_since defaults to 30 days ago.
Supplying any ship-date filter disables that default.
Response
{
"events": [ "..." ],
"retractions": [ "..." ],
"has_more": true,
"query": {
"domains": ["linear.app"],
"observed_since": "2026-07-01",
"observed_until": null,
"shipped_since": null,
"shipped_until": null,
"origin": "all",
"limit": 100,
"offset": 0
}
}
The query block echoes the filter that was actually applied, including any
defaults filled in for you.
Paging
Page with limit and offset. Ordering is stable across requests and across
rebuilds, so an offset means the same thing tomorrow. Continue while has_more
is true.
The event shape
Each event names one change and carries the evidence it was derived from.
{
"id": "evt_01KY4ESMC6P3X336MRW17MMTBR",
"domain": "vercel.com",
"organization_id": "ogn_01ARZ3NDEKTSV4RRFFQ69G5FAV",
"unit_id": null,
"product": "vercel",
"product_id": "ogn_01ARZ3NDEKTSV4RRFFQ69G5FAZ",
"scope_id": "ogn_01ARZ3NDEKTSV4RRFFQ69G5FAZ",
"type": "capability_expanded",
"area": "developer-experience",
"title": "Python function bundles now include precompiled bytecode",
"summary": "Vercel now precompiles Python function bundles to bytecode as part of the build, reducing per-invocation compilation overhead and cold-start latency for Python runtime functions. Corroborated by the @vercel/python@6.51.1 package release published the following day.",
"shipped_at": "2026-07-21",
"observed_at": "2026-07-22T08:19:31Z",
"origin": "observed",
"confidence": "high",
"evidence": {
"source_kind": "changelog",
"excerpt": "## Python function bundles now include precompiled bytecode"
},
"payload": {
"capability_slug": "function-runtimes",
"change": "Python function bundles now ship with precompiled bytecode, reducing cold-start compilation time."
}
}
| Field | Meaning |
|---|---|
id | Stable and unique. Safe to use for deduplication on your side. |
domain | The company, matching what you passed in domains. |
organization_id | Stable organization-graph ID. Additive; the domain remains present. |
unit_id | Nearest business-unit ancestor for the event scope, or null. |
product | Which of the company's products shipped it. See below — null is meaningful. |
product_id | Stable product graph ID, or null when product is null. Additive; the product slug remains present. |
scope_id | Exact graph node the event belongs to; may be an organization, business unit, brand, family or product. |
type | What kind of change it is. |
area | A functional area shared across companies, so the same concept is comparable between vendors. |
title | One line naming the change. |
summary | What changed, and how we corroborated it. |
origin | observed for changes we detected live, backfilled for history reconstructed from archives. |
confidence | high, medium or low. |
evidence | The source kind and the excerpt the event came from, so a claim can be checked rather than trusted. |
payload | Fields specific to the event type. |
What product means, and when it is null
A company that ships one product stamps it on every event, so grouping by
product never loses rows for those companies.
Where a company ships several, product names the one that shipped the change,
and null means the change could not be attributed to a single product —
either because it genuinely spans every or most of the products the company
ships, or because the source never says which one it belongs to. Both are the
same fact from a consumer's side: the vendor shipped something, and the product
is not determinable. 1.5% of events carry it.
Treat null as its own bucket rather than as a row to drop — filtering it out
discards real ships, and for a company shipping many products over shared
infrastructure it discards a lot of them.
The graph IDs are stable across renames and reparenting. They are resolved from
the one effective-dated organization graph as of the ship date where
available, otherwise the observation date. scope_id is the most precise join;
organization_id, unit_id and product_id are convenient projections of
its ancestor path. Existing domain and product values retain their legacy
behavior.
A capability that a vendor documents inside several products is recorded under each of them, not collapsed into one company-level row. That is deliberate: a change shipping for one product and not the others is a real event, and a collapsed row has nowhere to put it.
Event types
The types currently in the store, most common first:
capability_expanded, feature_added, capability_added, other,
new_integration, model_release, feature_removed, endpoint_added,
limit_change, price_change, endpoint_deprecated, plan_added,
capability_removed, new_product, feature_tier_change,
integration_removed, plan_removed.
other is a real ship that fits no more specific type — a third-party model
becoming available, a dated deprecation notice, an existing surface redesigned.
It is one of the larger types, so a filter that omits it drops real changes.
Treat the set as open. Filter on the types you care about rather than assuming this list is exhaustive.
Payloads carry the change structurally
A tier change records the movement, which makes questions like "what did competitors just un-gate" answerable directly:
{
"feature": "Devin Outposts",
"from_tiers": ["dedicated-tenant"],
"to_tiers": ["pro", "max", "teams", "dedicated-tenant"],
"direction": "opened_down"
}
A limit change records both sides, including a limit that was withdrawn rather than altered:
{
"limit": "copilot_5hr_tokens",
"old": "launch:50000, scale:2000000, max:4000000, enterprise:25000000",
"new": null,
"unit": "tokens/5h"
}
Ship date and observed date
Every event carries both dates, and they answer different questions.
observed_atis when we detected the change. This is the filter for staying current.shipped_atis when the vendor shipped it, where the source states a date. This is the filter for analysing a period.
The two diverge, sometimes by weeks. OpenAI's Codex Security plugin shipped on 4 June 2026 and appeared in the documentation on 28 July 2026. Combining the filters queries that gap directly:
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.docsignal.app/v1/events?observed_since=2026-07-01&shipped_until=2026-06-30"
Not every event reports a ship date. We always know when we saw a change; the
source does not always say when it shipped. Ship-date filters can only see the
events that carry one, and /v1/companies reports dated_events per company so
you can size that before relying on it.