Evolc Signals API & MCP
Company signals in your code and your AI assistant.
The same data as Signals: European companies that just started hiring for a function, opened a leadership role, raised money or turned profitable, with evidence for every signal. Ask Claude “which Czech and Slovak companies just started hiring SDRs?” or pull the list into your CRM. Company facts only, never personal data.
Plans and quotas
| Without an account | Free account | Work e-mail | Scout or Pipeline | |
|---|---|---|---|---|
| API & MCP calls | — | — | 200 calls / month | 10,000 calls / month |
| Companies per search | — | — | First 100 | All, paged |
| Accounts per account check | — | — | 1,000 | 5,000 |
| Revenue, growth and all evidence | — | — | ✓ | ✓ |
Verify your work e-mail: 14 days of full Signals free: the first account from each company gets 1,000 calls a month and every result for 14 days, no card needed. Quotas count every data request that returns results (REST call or MCP tool call; empty pages, unknown companies and our errors are free) per account per calendar month (UTC), across all of its keys (up to 5). Each key also allows 60 requests per minute. Results are gated exactly like the Signals page: total is always exact, and companies beyond your plan are counted in locked.
Authentication
Create a key on your API keys page. It starts with evk_ and is shown once; we store only a hash. Send it as a bearer token. Keys stop working when revoked, or when the account no longer has a verified work e-mail or a paid plan. The API is for servers: there are no CORS headers, so never put a key in browser code.
curl -s https://companies.evolc.com/api/v1/signals?countries=SK,CZ&families=sales&subs=sdr_bdr \
-H "Authorization: Bearer evk_…"GET /api/v1/signals
Companies with signals, strongest first. Lists are comma-separated; values in one list are OR, different filters are AND. Unknown parameters or values are a 400, never silently ignored.
| Parameter | Values |
|---|---|
countries | ISO-2 codes, e.g. SK,CZ,PL,HU,AT,DE (up to 12) |
industries | Industry keys, e.g. software_saas,fintech |
families | Job functions: engineering, data, product, design, sales, marketing, customer, operations, finance, people, legal, executive, robotics, manufacturing |
subs | Sub-roles of those functions, e.g. sdr_bdr, account_executive, customer_success, product_marketing |
kinds | hiring, first_in_function, hiring_spike, leadership_role_open, funding, revenue_jump, profitability_flip, director_change, news |
days | 7, 30, 90 (default 30) |
q | Name, website or one-liner contains (≤ 100 characters) |
since | Only signals newer than this ISO date, e.g. 2026-10-01 |
exclude_volume | 1 (default) leaves out volume hirers: staffing agencies, branch and field-sales networks, brokers, fundraisers. 0 includes them, marked "volume_hiring": true and ranked lower. |
limit, offset | 1–100 (default 25); offset ≤ 10 000. Use next for the next page. |
{
"items": [{
"id": "…", "name": "Acme s.r.o.", "domain": "acme.sk", "website": "https://acme.sk", "slug": "acme",
"country": "SK", "city": "Bratislava", "industry": "software_saas", "business_model": "b2b_saas",
"employee_band": "20-49", "founded_year": 2015, "one_liner": "…", "open_jobs": 4, "hot_score": 50,
"latest_revenue": 1250000, "revenue_growth": 0.42,
"hiring": [{ "family": "sales", "sub": "sdr_bdr", "open": 3, "new": 2 }],
"signals": [{ "kind": "hiring", "title": "SDR", "url": "https://acme.sk/jobs/sdr", "at": "2026-10-25T00:00:00Z" }],
"strength": 80, "last_signal_at": "2026-10-25T00:00:00Z",
"more_signals": 0, "financials_locked": false, "evolc_url": "https://companies.evolc.com/company/acme"
}],
"total": 240, "locked": 140, "next": 25, "window_days": 30,
"meta": { "tier": "work", "limit_remaining": 187, "quota": 200, "upgrade": "…" }
}GET /api/v1/companies/:slug and ?domain=
The public company profile, as on its Evolc page: description, industry, size, founded year, open jobs, highlights with evidence, filed financials (newest first) and sources. Leadership and other people are not included.
curl -s https://companies.evolc.com/api/v1/companies/acme -H "Authorization: Bearer evk_…"
curl -s "https://companies.evolc.com/api/v1/companies?domain=acme.sk" -H "Authorization: Bearer evk_…"GET /api/v1/searches
Your saved Signals searches with their filters (query uses the same names as /api/v1/signals). Free of quota, like key and MCP handshakes.
POST /api/v1/accounts
Check your own account list, for example a CRM export: which of these companies are hiring, raised money or grew, and which are quiet. The same matching as Your accounts: exact by domain (a website URL or an e-mail address at the company works too), otherwise by name within a country, otherwise by a unique name; never fuzzy. Your list is used only to answer the request and is not stored.
curl -s https://companies.evolc.com/api/v1/accounts -H "Authorization: Bearer evk_…" -H "content-type: application/json" -d '{"accounts":[{"domain":"acme.sk","ref":"crm-123"},{"name":"Globex","country":"CZ"}],"families":["sales"],"days":30}'| Field | Meaning |
|---|---|
accounts | 1 to your plan’s limit (1,000 with a work e-mail, 5,000 on Scout and Pipeline), each {domain?, name?, country?, ref?} with a domain or a name. ref is your record id, echoed back. |
families, subs, kinds, days, since, exclude_volume | As for /api/v1/signals. Countries, industries and q don’t apply to a known list. |
Answer: items in input order, each {ref, input, match: {company_id, slug, name, domain, country, confidence} | null, unmatched_reason, signals_in_window, company, locked}, plus matched, unmatched, with_signals, quiet, locked. confidence is domain, name_country or name (check those). Matched accounts are ranked (signals first by strength, then quiet ones by open roles) and the first 100 carry company on the work tier, all on paid plans; the rest are locked. Cost: one call per started 100 accounts.
Errors
Every error is JSON: {"error":{"code":"…","message":"…"}}, plus param for invalid parameters. Successful data calls return x-quota-limit and x-quota-remaining headers.
| Status | code | Meaning |
|---|---|---|
| 400 | invalid_parameter | Unknown parameter or value; see param. Does not use quota. |
| 401 | unauthorized, invalid_key | No bearer key, or a wrong or revoked one. |
| 403 | plan_required | The key's account no longer has a work e-mail or paid plan. |
| 404 | not_found | No such company or endpoint. |
| 429 | rate_limited, quota_exceeded | More than 60 requests a minute, or the monthly quota is used up. See retry-after. |
| 503 | unavailable | Signals are briefly unavailable; retry. |
MCP server for Claude and other AI assistants
A remote MCP server (Streamable HTTP) at https://companies.evolc.com/mcp, authenticated with OAuth (connect and sign in) or the same API key. Tools: search_signals, get_company, check_accounts, search_tenders, list_saved_searches. Each tool call counts as one API call; check_accounts takes up to 100 accounts per call.
Claude.ai, ChatGPT and other connectors (no key needed)
Add a custom connector with the URL https://companies.evolc.com/mcp, then sign in to Evolc and allow access. Claude.ai: Settings → Connectors → Add custom connector. ChatGPT: Settings → Apps & Connectors → Create. The app appears on your API keys page as a connected app, uses your plan’s quota, and is disconnected by revoking it there.
Claude Code
claude mcp add --transport http evolc https://companies.evolc.com/mcpRun /mcp in Claude Code to sign in. Or skip OAuth and send a key:
claude mcp add --transport http evolc https://companies.evolc.com/mcp --header "Authorization: Bearer evk_…"Claude Desktop
Add to claude_desktop_config.json (Settings → Developer → Edit config); mcp-remote bridges the remote server and sends the header.
{
"mcpServers": {
"evolc": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://companies.evolc.com/mcp", "--header", "Authorization:${EVOLC_AUTH}"],
"env": { "EVOLC_AUTH": "Bearer evk_…" }
}
}
}Other clients
Any client that supports Streamable HTTP and custom headers works: POST JSON-RPC to /mcp with Authorization: Bearer evk_…. The server is stateless (no sessions, no server-sent events) and supports protocol versions 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05.
Try: “Which companies in Czechia and Slovakia started hiring SDRs in the last 30 days and also raised money?”
Into your CRM: HubSpot, Pipedrive and others
No CRM app to install. On Scout and Pipeline there are two ways, and both work with HubSpot, Pipedrive and any CRM that imports files or has a Zapier, Make or n8n integration.
1. Import a CSV
On any search, account check or watchlist, open Export for HubSpot / Pipedrive. The files use the column names each CRM maps on its own:
| Format | Columns |
|---|---|
| HubSpot | Company name, Company Domain Name, City, Country/Region, Industry, Number of Employees, Description, Evolc signal, Evolc signal date, Evolc URL |
| Pipedrive | Organization - Name, Organization - Address, Organization - Evolc signal, Organization - Evolc signal date, Organization - Evolc URL |
- HubSpot: start an import from a file, choose one object, Companies, and upload the file. HubSpot updates companies that already exist with the same Company Domain Name. Create Evolc signal, Evolc signal date and Evolc URL as new company properties while mapping. HubSpot’s own Industry property accepts only its own list of values, so map our Industry column to a new text property. Number of Employees is the lower end of the company’s size band.
- Pipedrive: open Import data, choose From a spreadsheet and upload the file. Map the columns to Organization fields and create custom fields for the three Evolc columns. To avoid duplicates, import only new companies or use the webhook recipe below, which updates existing organizations.
2. Webhook → Zapier, Make or n8n → your CRM
- Create a webhook trigger: in Zapier Webhooks by Zapier → Catch Raw Hook (raw, so the signature can be checked), in Make a Custom webhook, in n8n a Webhook node. Copy its URL.
- In Signals, open a saved search or watchlist, add the URL under Delivery → Add webhook, copy the signing secret (shown once) and send a test.
- Check the signature in a code step (Zapier Code, n8n Code, or your own endpoint) with one of the snippets below, then loop over
items(Zapier Looping, Make Iterator, n8n Split Out). - For each company, search the CRM by domain (HubSpot) or by name (Pipedrive), then create the company if it is missing or update it if it exists, mapping the fields below.
| Payload field | HubSpot company | Pipedrive organization |
|---|---|---|
items[].name | Company name | Organization name |
items[].domain | Company Domain Name (the match key) | Website, or a custom “Domain” field to search on |
items[].city, items[].country | City, Country/Region | Address |
items[].signals[0].title | Evolc signal (custom property) | Evolc signal (custom field) |
items[].signals[0].at | Evolc signal date (custom property) | Evolc signal date (custom field) |
items[].evolc_url | Evolc URL (custom property) | Evolc URL (custom field) |
Each company is sent once per destination. Every delivery has its own Evolc-Delivery id. Company facts only, never personal data.
The payload
POST https://hooks.example.com/your-webhook
Content-Type: application/json
Evolc-Signature: t=1793174400,v1=5f2c…
Evolc-Delivery: 7b0e… (unique per delivery: ignore repeats)
{
"version": 1,
"type": "signals.digest", // "signals.test" for the test button
"id": "7b0e…",
"generated_at": "2026-10-28T06:00:00.000Z",
"search": { "id": "…", "name": "SDR hiring in CZ and SK", "kind": "search", "query": { … }, "url": "https://companies.evolc.com/signals?saved=…" },
"items": [
{
"name": "Example Logistics",
"domain": "example.com",
"website": "https://example.com",
"country": "CZ", "city": "Brno",
"industry": "logistics", "employee_band": "50-99", "one_liner": "…",
"open_jobs": 6,
"hiring": [{ "family": "sales", "sub": "sdr_bdr", "open": 3, "new": 2 }],
"signals": [{ "kind": "hiring", "title": "Started hiring sales: SDR/BDR", "url": "https://example.com/careers/…", "at": "2026-10-27T00:00:00Z" }],
"latest_revenue": 4200000, "revenue_growth": 0.18,
"strength": 82, "last_signal_at": "2026-10-27T00:00:00Z",
"evolc_url": "https://companies.evolc.com/company/example-logistics"
}
]
}Verify Evolc-Signature in Node.js
import crypto from 'node:crypto';
// rawBody: the request body exactly as received (a string, not re-serialised JSON).
// secret: the whsec_… signing secret shown when you added the webhook.
export function verifyEvolc(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries((header ?? '').split(',').map((p) => p.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const given = Buffer.from(parts.v1 ?? '', 'hex');
return given.length === 32 && crypto.timingSafeEqual(given, Buffer.from(expected, 'hex'));
}Verify Evolc-Signature in Python
import hashlib, hmac, time
# raw_body: the request body exactly as received (bytes).
# secret: the whsec_… signing secret shown when you added the webhook.
def verify_evolc(raw_body: bytes, header: str, secret: str, tolerance_seconds: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in (header or "").split(",") if "=" in p)
try:
t = int(parts["t"])
except (KeyError, ValueError):
return False
if abs(time.time() - t) > tolerance_seconds:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))