Signals API [BETA]
Retrieve news and data-change signals for companies.
This document describes the two read-only signals endpoints under /api/v3/signals/:
/api/v3/signals/news/— news-style signals/api/v3/signals/data-changes/— company data-change signals
Both endpoints share the same query and pagination model. They are intended for clients that want to stream signals across companies the user has access to, optionally constrained with VQL (Vainu Query Language) filters.
Quick decision guide
- Use
signals/newsto retrieve human-authored news articles, contracts and other externally sourced events that have been linked to companies. - Use
signals/data-changesto retrieve programmatically generated signals derived from changes in company master data (for example, a new financial figure, a registry change, or a new key person).
Authentication
Query parameters
The same parameters are accepted as JSON body (preferred), URL-encoded query string parameters, or a mix.
| Parameter | Type | Default | Description |
|---|---|---|---|
query | VQL object or JSON string | — | Filter query. See filtering-company-data. |
limit | integer (1–100) | 20 | Maximum number of items returned. |
offset | integer (0–100000) | 0 | Number of items to skip for pagination. |
format | json (default) or jsonl | json | Response renderer. jsonl streams one JSON object per line. |
Filtering with VQL
The query parameter accepts a VQL operation tree. The most common building blocks:
-
business_ids— prefixed business ids (e.g.FI75432000). -
countries— country codes the linked companies belong to -
tags— signal tag ids. -
vainu_date— ISO date or datetime string for time-windowing.
Response
200 OK— a streaming JSON array (or JSON Lines, whenformat=jsonl). The body is produced incrementally; clients should consume it as a stream rather than buffering.400 Bad Request— invalid query, invalid order field, business-id scope mismatch (Vainu View tokens), or other validation error.401 Unauthorized— missing or invalid credentials.- An empty array (or empty body for JSONL) is returned when the query matches nothing or when the underlying Mongo query times out.
The tags field
tags fieldtags is a list field, so a signal matches a tag filter when any of its tags matches. Values are integers;
numeric strings ("43543") are accepted and coerced.
Tag ids are global — the same id means the same thing on both endpoints, and the ids are the same ones used by the Vainu platform UI and by list/trigger definitions.
Tag reference
news— produced on news signals (/signals/news/)data-changes— produced only on generated signals (/signals/data-changes/)both— appears on either endpoint
| Tag id | Name | Endpoint |
|---|---|---|
8000080 | Change of Company Form | data-changes |
8000072 | Change of Company Name | data-changes |
8000069 | Change of Status | data-changes |
8000060 | New Auxiliary Name | data-changes |
8000040 | Achieved 1MEUR Turnover | data-changes |
8000010 | Bankruptcy | news |
8000025 | Decline in Sales or Market Share | news |
8000024 | Earnings Release | news |
6967635 | EU funding | news |
4507212 | Financial (Equity) Arrangements | news |
8000018 | Growth in Sales or Market Share | news |
8000049 | Late Registration of Financial Statement | data-changes |
43536 | Layoffs | news |
8000037 | New Financial Statement | data-changes |
2943080 | Protest list | news |
8000016 | Public Decision on Financing | news |
8000022 | Change in Strategy | news |
8000085 | Construction Project | news |
43543 | Funding | news |
43544 | Internationalization | news |
8000020 | Investment - Machines and equipment | news |
8000019 | Investment - New Place of Business | news |
8000021 | Investment – Software | news |
8000077 | IPO | news |
77883 | Mergers & Acquisitions | news |
8000050 | New Company Established | data-changes |
8000015 | Events | news |
2999389 | Registered web-address / domain | news |
8000029 | Legal Dispute | news |
2932622 | New Product / Service | news |
4507192 | Partnerships | news |
8000002 | Real Estate Transactions | news |
3325073 | Relocation | both |
8000076 | Stock Trade | news |
43545 | Won Contracts | news |
8000071 | Apartment sales notice | news |
43551 | Awards | news |
6931739 | Change in Credit Rating | news |
8000090 | Environmental Impact Assessment | news |
8000081 | Granted Energy Certificate | data-changes |
8000058 | New Vehicle | data-changes |
8000086 | Temporary exceptions in business | news |
6067468 | Change in Legislation | news |
2940230 | Government & Public Contract Notices | news |
8000056 | Granted Alcohol License | data-changes |
8000053 | Granted Cargo Transport License | data-changes |
8000052 | Granted Public Transport License | data-changes |
8000054 | Granted social services or health services license | data-changes |
8000051 | Granted Taxi License | data-changes |
6944439 | Minutes | news |
8000068 | New Trademark | data-changes |
8000013 | Patents | news |
7200000 | Permit | both |
8000039 | Change in Board of Directors | both |
8000038 | Change of CEO | both |
77884 | Changes in Personnel | both |
6893088 | Key Person Appointment | news |
8000034 | Key Person Departure | news |
43535 | Open Positions | news |
8000075 | New Advertising Technology | data-changes |
8000066 | New Analytics Tool | data-changes |
8000064 | New ATS Tool | data-changes |
8000062 | New Chat and Support Tool | data-changes |
8000063 | New CMS Platform | data-changes |
8000083 | New CRM Technology | data-changes |
8000061 | New e-commerce technology | data-changes |
8000059 | New Marketing Automation Tool | data-changes |
8000074 | New Payment Technology | data-changes |
8000073 | New Reservation Technology | data-changes |
8000065 | New Server Technology | data-changes |
8000084 | New Social Media Channel | data-changes |
4467311 | New Technology | both |
Filtering signals by tag
Both v3 signals endpoints classify every signal with tags — integer ids such as 43543 (Funding) or
8000038 (Change of CEO).
Including tags
Use ?IN with a list of tag ids. A signal matches if it carries at least one of them (logical OR).
{
"query": {
"?ALL": [
{"?IN": {"tags": [43543, 77883]}}
]
}
}Funding or Mergers & Acquisitions signals.
?EQ matches a single tag and is equivalent to a one-element ?IN:
{"?ALL": [{"?EQ": {"tags": 43543}}]}Requiring several tags at once
Repeat the tag operation inside ?ALL — each entry must match, so the signal has to carry all listed tags:
{
"query": {
"?ALL": [
{"?IN": {"tags": [43543]}},
{"?IN": {"tags": [43535]}}
]
}
}Signals tagged both Funding and Open Positions.
Note the difference: {"?IN": {"tags": [43543, 43535]}} is OR, two separate ?IN entries under ?ALL is AND.
Excluding tags
Wrap the tag operation in ?NOT. This is the standard way to filter out unwanted signal types:
{
"query": {
"?ALL": [
{"?NOT": {"?IN": {"tags": [43535, 77884]}}}
]
}
}Everything except Open Positions and Changes in Personnel signals.
Signals with no tags at all are also returned by an exclusion filter, because an empty tags array does not
contain any of the excluded ids.
?NOT around ?EQ excludes a single tag:
{"?ALL": [{"?NOT": {"?EQ": {"tags": 43535}}}]}Combining include and exclude
The most common real-world shape — include a topic set, subtract the noise, and window by date:
{
"query": {
"?ALL": [
{"?IN": {"tags": [43543, 77883, 8000019]}},
{"?NOT": {"?IN": {"tags": [43535]}}},
{"?GTE": {"vainu_date": "2026-01-01"}},
{"?IN": {"business_ids": ["FI26550449", "SE5560000009"]}}
]
},
"limit": 100,
}Include and exclude clauses within the same ?ALL are AND-ed, so a signal must match every clause.
Signals with or without tags
?EXISTS checks whether the signal has any tags:
{"?ALL": [{"?EXISTS": {"tags": true}}]}true→ only signals that have at least one tagfalse→ only signals with an empty or missingtagsarray
Filtering Signals with Tags Example
query may be sent as a JSON object in the request body or as a URL-encoded JSON string. These are equivalent:
import requests
# JSON body (GET with body, or POST — both are treated as list requests)
response = requests.post(
"https://api.vainu.io/api/v3/signals/news/",
headers={"Authorization": f"Bearer {token}"},
json={
"query": {
"?ALL": [
{"?IN": {"tags": [43543]}},
],
},
"limit": 50,
},
)
response.raise_for_status()
signals = response.json()1) News signals API
Base path: /api/v3/signals/news/
Returns news-style signals from the lead collection, ordered by vainu_date descending by default.
Item schema
Each item contains:
| Field | Type | Description |
|---|---|---|
id | string | Mongo _id of the signal. |
title | string | Signal title, with translation placeholders resolved. |
content | string | Signal body text. May be truncated to 10 characters for GDPR-restricted domains. |
link | string | Source URL of the article or document. |
vainu_date | datetime | Vainu-assigned timestamp of the event. |
tags | array of {id, value} | Topical tags attached to the signal (e.g. funding, new key person). |
organizations | array of objects | Companies linked to the signal. Each item contains business_id, country, logo_url, name. |
Example
import requests
response = requests.post(
"https://api.vainu.io/api/v3/signals/news/",
headers={"Authorization": f"Bearer {token}"},
json={
"query": {
"?ALL": [
{"?IN": {"business_ids": ["FI25578642", "FI28229966"]}},
{"?GTE": {"vainu_date": "2026-01-01"}},
],
},
"limit": 10,
},
)
response.raise_for_status()
signals = response.json()Sample response (truncated):
[
{
"id": "65f0a1b2c3d4e5f6a7b8c9d0",
"title": "Acme Oy raises 12 M€ Series B",
"content": "Acme Oy announced today...",
"link": "https://example.com/articles/acme-series-b",
"vainu_date": "2026-04-22T08:15:00Z",
"tags": [{"id": 4123, "value": "Funding"}],
"organizations": [
{
"business_id": "FI12345678",
"country": "FI",
"logo_url": "https://...",
"name": "Acme Oy"
}
]
}
]2) Data-change signals API
Base path: /api/v3/signals/data-changes/
Returns generated signals from the generated_lead collection, ordered by vainu_date descending by default. These signals are produced when monitored fields on a company record change (for example, revenue update, CEO change, new registration data).
Item schema
Each item contains:
| Field | Type | Description |
|---|---|---|
id | string | Mongo _id of the generated signal. |
title | string | Human-readable headline rendered in English from dynamic_values and tags. |
content | string | Human-readable body rendered in English from dynamic_values and tags. |
vainu_date | datetime | Vainu-assigned timestamp of the change event. |
tags | array of {id, value} | Topical tags describing the kind of change. |
organizations | array of objects | Companies linked to the signal. Each item contains business_id, country, logo_url, name. |
dynamic_values | array of objects | Raw structured representation of the change. Each entry typically carries a key, a type, and old/new values, e.g. {"key": "revenue", "old_revenue": 1000000, "revenue": 1500000, "currency_code": "EUR"}. |
Example
import requests
response = requests.post(
"https://api.vainu.io/api/v3/signals/data-changes/",
headers={"Authorization": f"Bearer {token}"},
json={
"query": {
"?ALL": [
{"?IN": {"business_ids": ["FI12345678"]}},
{"?GTE": {"vainu_date": "2026-01-01"}},
],
},
"limit": 20,
},
)
response.raise_for_status()
signals = response.json()Sample response (truncated):
[
{
"id": "66001a2b3c4d5e6f7a8b9c0d",
"title": "Vainu Finland Oy revenue increased",
"content": "Vainu Finland Oy reported revenue growth from 1.0 M€ to 1.5 M€.",
"vainu_date": "2026-03-30T00:00:00Z",
"tags": [{"id": 5567, "value": "Financial growth"}],
"organizations": [
{
"business_id": "FI12345678",
"country": "FI",
"logo_url": "https://...",
"name": "Acme Oy"
}
],
"dynamic_values": [
{
"type": "revenue_change",
"key": "revenue",
"old_revenue": 1000000,
"revenue": 1500000,
"currency_code": "EUR"
}
]
}
]Pagination, streaming, and exports
- Use
limitandoffsetfor normal pagination, up to a maximum offset of100000. - For larger exports, prefer
format=jsonlwith a moderatebatch_size(for example1000) so results stream as they leave the database. - Sorting is required for stable pagination; the default
-vainu_dateis appropriate for most clients.
Updated 4 days ago