{"openapi":"3.1.0","info":{"title":"Rodz API","description":"\nGenerate leads from intent signals with Rodz.io\n\n## Authentication\n\nAll API requests require a Bearer token:\n\n```\nAuthorization: Bearer USR_xxxxxxxxxxxxx\n```\n\nGenerate API keys from **Integrations → API** in the dashboard.\n\n## Rate Limits\n\n| Limit | Value |\n|-------|-------|\n| Per second | 100 requests |\n\nLimit is enforced per API key on a sliding 1-second window.\nExceeding it returns `429 Too Many Requests` with `Retry-After: 1`.\n\nEnrichment lookups that take several seconds (for example `GET /api/v1/enrichment/contact`\nwith `freshness=live`, or `GET /api/v1/enrichment/firmographic`) also have a cap on how many\nrun **at the same time** per API key. A call above it is answered at once with\n`429 Too Many Requests`, error code `TOO_MANY_CONCURRENT_REQUESTS` and a `Retry-After`\nheader: wait that many seconds and send it again. For large lists, keep a steady number of\ncalls in flight (10 is a safe start) or use `POST /api/v1/enrichment/contacts/bulk`.\n\n## Webhooks\n\nWhen a signal generates leads, they are POSTed to the `webhookUrl` you provide when creating the signal. See the **Callbacks** section on each signal-creation endpoint for the exact typed payload schema.\n\n### Testing & Management\n\n| Endpoint | Description |\n|---|---|\n| `POST /v1/signals/{id}/test-webhook` | Send a test payload (`is_test: true`) to verify your endpoint |\n| `POST /v1/signals/{id}/replay-webhook` | Resend all existing leads to the webhook (`is_replay: true`) |\n\n### Webhook Signature Verification\n\nEvery webhook request includes HMAC-SHA256 signature headers so you can verify it came from Rodz:\n\n| Header | Description |\n|--------|-------------|\n| `X-Webhook-Signature` | HMAC-SHA256 hex digest |\n| `X-Webhook-Timestamp` | Unix timestamp used in signing |\n\n**Verification algorithm:**\n\n```python\nimport hmac, hashlib\n\ndef verify(body_bytes, signature, timestamp, webhook_secret):\n    message = f\"{timestamp}.\".encode(\"utf-8\") + body_bytes\n    expected = hmac.new(\n        webhook_secret.encode(\"utf-8\"),\n        message,\n        hashlib.sha256,\n    ).hexdigest()\n    return hmac.compare_digest(expected, signature)\n```\n\n**Where to find your webhook secret:** Each API key has a webhook secret generated automatically. View it in **Integrations → API** in the dashboard, or regenerate it from the same page.\n\n### Retries & Idempotency\n\nEvery delivery includes an `X-Webhook-Id` header:\n\n| Header | Description |\n|--------|-------------|\n| `X-Webhook-Id` | Stable delivery identifier — **the same on the first attempt and on every retry**. |\n\nIf a delivery fails **transiently** (a timeout, or a `5xx` response), Rodz retries it automatically with exponential backoff before giving up. Because of this, the **same lead can be delivered more than once** — always **deduplicate on `X-Webhook-Id`**.\n\n- A `2xx` marks the delivery as successful.\n- A non-`2xx` `4xx` (e.g. bad URL, auth, or validation) is treated as **permanent** and is **not** retried.\n- Return `429` if you want Rodz to slow down and retry shortly.\n\n### Best Practices\n\n- **Return 2xx quickly** — perform heavy processing asynchronously. Non-2xx responses are treated as delivery failures.\n- **Deduplicate on `X-Webhook-Id`** — retries mean the same lead may arrive more than once; treat delivery as at-least-once.\n- **Verify signatures** — always validate `X-Webhook-Signature` using your webhook secret to ensure payloads are authentic.\n- **Signal back-pressure with `429`** — return `429` to have Rodz back off and retry rather than drop the lead.\n\n## Error Responses\n\nAll errors follow this format:\n\n```json\n{\n  \"error\": {\n    \"code\": \"INVALID_REQUEST\",\n    \"message\": \"Detailed error description\"\n  }\n}\n```\n\n### Common Error Codes\n\n| Code | Status | Description |\n|------|--------|-------------|\n| `UNAUTHORIZED` | 401 | Invalid or missing API key |\n| `FORBIDDEN` | 403 | API key lacks permission |\n| `NOT_FOUND` | 404 | Resource not found |\n| `RATE_LIMITED` | 429 | Too many requests |\n| `INVALID_REQUEST` | 400 | Validation error |\n\n## Pagination\n\nList endpoints support pagination:\n\n```\nGET /api/v1/signals?limit=10&offset=0\n```\n\n## MCP Integration — connect Rodz to Claude, Cursor or Claude Code\n\nRodz runs a hosted MCP (Model Context Protocol) server, so an AI assistant can set up and tune signals, read their leads, check your credits and enrich people and companies — in plain language.\n\n- **URL:** `https://api.rodz.io/mcp` (Streamable HTTP)\n- **Authentication — two ways, same URL:**\n  - **Sign in with your Rodz account (OAuth)** — for Claude on the web, Claude Desktop and the Claude mobile apps. Nothing to copy: you add the URL, sign in to Rodz and click **Allow**. The connection then appears under **Settings → Connected apps** in the dashboard, where you can revoke it at any time.\n  - **Your Rodz API key**, sent as `Authorization: Bearer USR_...` — for Claude Code, Cursor and other tools that let you set a header (create a key under **Integrations → API** in the dashboard).\n\n  Either way every tool call is an ordinary API call on your account: same account, same rate limits, same credit prices as the REST API. Tools that spend credits state their price in their description.\n- **Tools (24):** `list_signal_types`, `list_personas`, `list_industries`, `list_technographic_tools`, `list_signals`, `get_signal`, `create_signal`, `update_signal`, `pause_signal`, `resume_signal`, `delete_signal`, `get_signal_funnel`, `list_signal_leads`, `list_watched_companies`, `add_watched_companies`, `get_credit_balance`, `get_credit_usage`, `enrich_contact`, `enrich_company`, `find_email`, `search_companies`, `search_people`, `start_phone_lookup`, `get_phone_lookup_result`.\n\n### Claude (web, desktop, mobile) — custom connector\n\n1. In Claude, open **Settings → Connectors** and click **Add custom connector** (on Team and Enterprise plans an owner adds it under **Organization settings → Connectors**, then each member connects).\n2. Name it `Rodz` and paste the URL `https://api.rodz.io/mcp`. Leave the advanced OAuth fields empty, then click **Add**.\n3. Click **Connect**: a Rodz window opens. Sign in if asked, check the account shown, and click **Allow**.\n4. In a chat, enable Rodz from the tools menu and ask, for example, *\"List my active signals and how many leads each delivered this week.\"*\n\nThe connector added on claude.ai is also available in Claude Desktop and the mobile apps.\n\n### Claude Code\n\n```bash\nclaude mcp add --transport http rodz https://api.rodz.io/mcp \\\n  --header \"Authorization: Bearer USR_your_api_key_here\"\n```\n\nWithout the `--header`, Claude Code signs in with your Rodz account instead (run `/mcp` in Claude Code and choose **Authenticate**).\n\n### Cursor\n\nIn `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (one project):\n\n```json\n{\n  \"mcpServers\": {\n    \"rodz\": {\n      \"url\": \"https://api.rodz.io/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer USR_your_api_key_here\" }\n    }\n  }\n}\n```\n\n### Claude Desktop with an API key (optional)\n\nPrefer the custom connector above. To use an API key instead, Claude Desktop reaches the hosted server through the open-source `mcp-remote` bridge (requires Node.js 18+). Add this to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows), then restart Claude Desktop:\n\n```json\n{\n  \"mcpServers\": {\n    \"rodz\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-remote\", \"https://api.rodz.io/mcp\", \"--header\", \"Authorization:${RODZ_AUTH}\"],\n      \"env\": { \"RODZ_AUTH\": \"Bearer USR_your_api_key_here\" }\n    }\n  }\n}\n```\n\n### Local package (alternative)\n\nThe npm package `@rodzio/mcp-server` still works. It runs on your machine and exposes every REST endpoint as a tool:\n\n```bash\nclaude mcp add -e RODZ_API_KEY=USR_your_api_key_here rodz -- npx -y @rodzio/mcp-server\n```\n\nor, in `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"rodz\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@rodzio/mcp-server\"],\n      \"env\": { \"RODZ_API_KEY\": \"USR_your_api_key_here\" }\n    }\n  }\n}\n```\n\n### Integration skill for AI coding assistants\n\nBuilding a Rodz integration with Claude or another agent? Give it the **rodz-integration** skill: the core flows, webhook verification, watchlists, enrichment, errors and credit rules, with copy-paste examples. Download `https://api.rodz.io/v1/skills/rodz-integration/download` (a `.skill` archive) and add it to your assistant's skills. It checks `https://api.rodz.io/v1/skills/rodz-integration/version` when it starts, so it follows corrections to these docs without a reinstall.\n\n### Usage\n\nExample prompts:\n- \"Which signal types would tell me a company is about to buy a CRM? Set one up for SaaS companies in France, as a draft.\"\n- \"Show me the leads my job-change signal found since yesterday.\"\n- \"Why is my fundraising signal so quiet? Relax the filter that removes the most.\"\n- \"Find the VP Sales at these five accounts and their professional emails.\"\n","version":"29411a55f6371a4048c35ed36fa29c25531f1e76"},"paths":{"/api/v1/signals/account-watchlist":{"post":{"tags":["Signals"],"summary":"Create Account Watchlist signal","description":"Upload your accounts once and hear about everything that happens to them - one list, one daily budget, one set of destinations.\n\nEvery other watchlist answers one question about your accounts: did they raise, are they hiring, did someone join. This one asks all of them at once, so you stop maintaining the same company list in a dozen places and stop reconciling a dozen webhooks.\n\n**Input:** `companies` (a name, a domain, or a LinkedIn company URL per entry - send the LinkedIn URL whenever you have it, it is the only one of the three that separates two companies sharing a name - or an object `{name, domain, linkedinUrl}` carrying all three; strings and objects can be mixed), `sources` (which events to watch - omit it for the defaults), `firstRunLookbackDays` (default 180), `dailyLeadLimit`, plus persona and enrichment flags (`targetPersonas`, `getEmails`, `getPhones`) which apply to every event.\n\n**Events you can switch on**, as keys of `sources`: `fundraising`, `mergers_acquisitions`, `forecasted_funding`, `forecasted_ipo`, `forecasted_acquisition`, `forecasted_growth`, `public_tenders`, `job_offers`, `recruitment_campaign`, `new_decision_makers`, `company_post_reactions`, `competitor_social_reactions`, `competitor_connections`, `company_news`. Each entry is an object taking `enabled`. Every event except `company_news` is on by default, so omit `sources` to watch for all of them and send it only to switch some off. `company_news` (funding, acquisitions, new locations, leadership changes, launches, contracts, restructuring and upcoming trade shows reported in the news, each checked against the article itself) is off unless you send `{\"company_news\": {\"enabled\": true}}`. `competitor_connections` is the slowest to produce - the relationships it reports build over weeks - so expect it to be quiet at first.\n\n**Output:** every event at a watched company is pushed to your `webhookUrl` as an ordinary lead. `signal.id` and `signal.type` always identify THIS watchlist, whichever event fired, so one handler covers the whole list; `signal.last_signal` names the event, and is the field to switch on. `company` is always populated; `contact` is the empty string for company-level events (a funding round, a tender) and a contact object for person-level ones (a new decision maker, a post reactor, or any event with persona targeting on).\n\n**Billing:** a flat 3 credits per lead, whichever event produced it. The `dailyLeadLimit` is ONE budget across every event you enabled, not one per event.\n\nThe first check reaches back `firstRunLookbackDays` and delivers the matching events from that window, so an uploaded list is worth something the same day; later checks deliver only what is new. It is bounded on purpose - an unbounded first run would bill you for years of history the moment you save.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.","operationId":"create_account_watchlist_signal_api_v1_signals_account_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/AccountWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"AccountWatchlistCreate","examples":[{"config":{"companies":["https://www.linkedin.com/company/doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"Lemlist"],"firstRunLookbackDays":180,"getEmails":true,"sources":{"competitor_connections":{"enabled":false},"fundraising":{"enabled":true},"job_offers":{"enabled":true},"mergers_acquisitions":{"enabled":true},"new_decision_makers":{"enabled":true}},"targetPersonas":["Sales Director"]},"dailyLeadLimit":50,"name":"My key accounts","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"My key accounts","value":{"name":"My key accounts","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"companies":["https://www.linkedin.com/company/doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"Lemlist"],"sources":{"fundraising":{"enabled":true},"mergers_acquisitions":{"enabled":true},"job_offers":{"enabled":true},"new_decision_makers":{"enabled":true},"competitor_connections":{"enabled":false}},"firstRunLookbackDays":180,"targetPersonas":["Sales Director"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My key accounts","status":"active","signalTypeId":"account_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"sources":{"fundraising":{"enabled":true},"mergers_acquisitions":{"enabled":true},"job_offers":{"enabled":true},"new_decision_makers":{"enabled":true},"competitor_connections":{"enabled":false}},"firstRunLookbackDays":180,"targetPersonas":["Sales Director"],"getEmails":true},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent for each event at one of your watched companies. `signal.id` and `signal.type` are always this watchlist; `signal.last_signal` names the event that fired and is the field to switch on. `contact` is the empty string for company-level events.","operationId":"account_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"funding_type":{"type":"string","title":"Funding Type","description":"Round type when a funding event fired (e.g. \"seed\")","default":""},"funding_amount_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount Usd","description":"Round size in USD when a funding event fired; \"\" otherwise","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD) for funding and deal events","default":""},"deal_type":{"type":"string","title":"Deal Type","description":"Deal type when an M&A event fired","default":""},"watchlist_role":{"type":"string","title":"Watchlist Role","description":"Which side of the deal your watched company was on: \"acquiree\" or \"acquirer\". Empty for every other event.","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When a new decision maker started the role, as the profile publishes it (\"MM/YYYY\", e.g. \"05/2026\"). Empty for every other event.","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Same month as `new_job_started_on`, always \"YYYY-MM\" (e.g. \"2026-05\"). Empty for every other event.","default":""},"news_event_type":{"type":"string","title":"News Event Type","description":"News event type (`funding`, `mergers_acquisitions`, `expansion`, `leadership_change`, `product_launch`, `contract_partnership`, `restructuring`, `event_participation`) when a news event fired","default":""},"news_event_label":{"type":"string","title":"News Event Label","description":"Human-readable news event type","default":""},"news_event_date":{"type":"string","title":"News Event Date","description":"Date of the news event (YYYY-MM-DD) when a news event fired","default":""},"news_headline":{"type":"string","title":"News Headline","description":"One factual sentence describing the news event when one fired","default":""},"news_url":{"type":"string","title":"News Url","description":"The article the news event was verified against, when one fired","default":""},"news_title":{"type":"string","title":"News Title","description":"The article's own title, when a news event fired","default":""},"news_summary":{"type":"string","title":"News Summary","description":"A short summary of what the article says about the event, when a news event fired — ready to ground an outreach message","default":""},"news_event_name":{"type":"string","title":"News Event Name","description":"Upcoming trade show or conference name (`event_participation` only)","default":""},"news_event_location":{"type":"string","title":"News Event Location","description":"Where that trade show or conference is held (`event_participation` only)","default":""},"post_url":{"type":"string","title":"Post Url","description":"Post URL when a social engagement event fired","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published (YYYY-MM-DD) when a social event fired","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"How the person engaged (e.g. \"like\", \"comment\") on social events","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookAccountWatchlistSignal","description":"Signal block for account_watchlist — a union, declared honestly.\n\nOne watchlist emits several kinds of event, so the fields present depend on\nwhich one fired. Rather than pretend otherwise (or document only the common\ncore and let integrators discover the rest in production), every field that\nCAN appear is declared here and defaults to the empty string.\n\n``last_signal`` on the base is what says which set is populated. Read it\nfirst; treat everything below as present-but-empty otherwise.\n\nInherits the ``job_offer_*`` fields from the job signal, which the job-offer\nand recruitment events populate."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookAccountWatchlistPayload","description":"Webhook payload for account_watchlist.\n\nOne signal, several kinds of event. ``signal.type`` is always\n``account_watchlist`` and ``signal.id`` is always the id you got back when\nyou created it — the delivery is identified by the signal YOU made, never by\nthe internal one that produced it.\n\n**Switch on ``signal.last_signal``**, which names the event that fired:\n`Watched Company Raised`, `Watched Company Deal`, `Job Offer`,\n`Recruitment Campaign`, `New Decision Maker Watchlist`,\n`Public Tenders Watchlist`, `Watched Company Likely to Raise`,\n`Watched Company on a Path to IPO`,\n`Watched Company Likely Acquisition Target`,\n`Watched Company Expected to Scale`, `Company Post Reactions`,\n`Competitor Social Reactions`, `Competitor Relationship Monitoring`.\n\n``company`` is always populated — every event here happens TO a company on\nyour list, which is the one thing every delivery has in common.\n\n``contact`` is the empty string ``\"\"`` for company-level events (a funding\nround, a tender, a job posting with persona targeting off) and a contact\nobject for person-level ones (a new decision maker, someone reacting to a\npost, or any event with persona targeting enabled). Test for the empty\nstring rather than assuming a person is present.\n\nEvent-specific fields ride on ``signal`` and vary with ``last_signal``:\nfunding events populate the funding fields, job events the ``job_offer_*``\nones, social events ``post_url``. Every one of them is declared on\n``WebhookAccountWatchlistSignal`` and defaults to the empty string, so a\nfield being empty never means it is missing.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"","created_at":"2026-05-31T14:30:00+00:00","email":"","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":""},"signal":{"announcement_date":"2026-08-17","funding_amount_usd":32000000,"funding_type":"series_b","id":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e","last_signal":"Watched Company Raised","last_signal_date":"2026-08-18","name":"My key accounts","type":"account_watchlist"}}]},"example":{"signal":{"id":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e","name":"My key accounts","type":"account_watchlist","last_signal":"Watched Company Raised","last_signal_date":"2026-08-18","funding_type":"series_b","funding_amount_usd":32000000,"announcement_date":"2026-08-17"},"contact":{},"company":{"name":"Doctolib","website":"https://www.doctolib.fr","linkedin_url":"https://www.linkedin.com/company/doctolib","industry":"Health Care","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"funding_type":{"type":"string","title":"Funding Type","description":"Round type when a funding event fired (e.g. \"seed\")","default":""},"funding_amount_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount Usd","description":"Round size in USD when a funding event fired; \"\" otherwise","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD) for funding and deal events","default":""},"deal_type":{"type":"string","title":"Deal Type","description":"Deal type when an M&A event fired","default":""},"watchlist_role":{"type":"string","title":"Watchlist Role","description":"Which side of the deal your watched company was on: \"acquiree\" or \"acquirer\". Empty for every other event.","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When a new decision maker started the role, as the profile publishes it (\"MM/YYYY\", e.g. \"05/2026\"). Empty for every other event.","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Same month as `new_job_started_on`, always \"YYYY-MM\" (e.g. \"2026-05\"). Empty for every other event.","default":""},"news_event_type":{"type":"string","title":"News Event Type","description":"News event type (`funding`, `mergers_acquisitions`, `expansion`, `leadership_change`, `product_launch`, `contract_partnership`, `restructuring`, `event_participation`) when a news event fired","default":""},"news_event_label":{"type":"string","title":"News Event Label","description":"Human-readable news event type","default":""},"news_event_date":{"type":"string","title":"News Event Date","description":"Date of the news event (YYYY-MM-DD) when a news event fired","default":""},"news_headline":{"type":"string","title":"News Headline","description":"One factual sentence describing the news event when one fired","default":""},"news_url":{"type":"string","title":"News Url","description":"The article the news event was verified against, when one fired","default":""},"news_title":{"type":"string","title":"News Title","description":"The article's own title, when a news event fired","default":""},"news_summary":{"type":"string","title":"News Summary","description":"A short summary of what the article says about the event, when a news event fired — ready to ground an outreach message","default":""},"news_event_name":{"type":"string","title":"News Event Name","description":"Upcoming trade show or conference name (`event_participation` only)","default":""},"news_event_location":{"type":"string","title":"News Event Location","description":"Where that trade show or conference is held (`event_participation` only)","default":""},"post_url":{"type":"string","title":"Post Url","description":"Post URL when a social engagement event fired","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published (YYYY-MM-DD) when a social event fired","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"How the person engaged (e.g. \"like\", \"comment\") on social events","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookAccountWatchlistSignal","description":"Signal block for account_watchlist — a union, declared honestly.\n\nOne watchlist emits several kinds of event, so the fields present depend on\nwhich one fired. Rather than pretend otherwise (or document only the common\ncore and let integrators discover the rest in production), every field that\nCAN appear is declared here and defaults to the empty string.\n\n``last_signal`` on the base is what says which set is populated. Read it\nfirst; treat everything below as present-but-empty otherwise.\n\nInherits the ``job_offer_*`` fields from the job signal, which the job-offer\nand recruitment events populate."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookAccountWatchlistPayload","description":"Webhook payload for account_watchlist.\n\nOne signal, several kinds of event. ``signal.type`` is always\n``account_watchlist`` and ``signal.id`` is always the id you got back when\nyou created it — the delivery is identified by the signal YOU made, never by\nthe internal one that produced it.\n\n**Switch on ``signal.last_signal``**, which names the event that fired:\n`Watched Company Raised`, `Watched Company Deal`, `Job Offer`,\n`Recruitment Campaign`, `New Decision Maker Watchlist`,\n`Public Tenders Watchlist`, `Watched Company Likely to Raise`,\n`Watched Company on a Path to IPO`,\n`Watched Company Likely Acquisition Target`,\n`Watched Company Expected to Scale`, `Company Post Reactions`,\n`Competitor Social Reactions`, `Competitor Relationship Monitoring`.\n\n``company`` is always populated — every event here happens TO a company on\nyour list, which is the one thing every delivery has in common.\n\n``contact`` is the empty string ``\"\"`` for company-level events (a funding\nround, a tender, a job posting with persona targeting off) and a contact\nobject for person-level ones (a new decision maker, someone reacting to a\npost, or any event with persona targeting enabled). Test for the empty\nstring rather than assuming a person is present.\n\nEvent-specific fields ride on ``signal`` and vary with ``last_signal``:\nfunding events populate the funding fields, job events the ``job_offer_*``\nones, social events ``post_url``. Every one of them is declared on\n``WebhookAccountWatchlistSignal`` and defaults to the empty string, so a\nfield being empty never means it is missing.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"","created_at":"2026-05-31T14:30:00+00:00","email":"","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":""},"signal":{"announcement_date":"2026-08-17","funding_amount_usd":32000000,"funding_type":"series_b","id":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e","last_signal":"Watched Company Raised","last_signal_date":"2026-08-18","name":"My key accounts","type":"account_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/ai-adoption":{"post":{"tags":["Signals"],"summary":"Create AI Adoption signal","description":"Reach companies as they put AI tooling into production — the moment budget, urgency and executive attention line up.\n\n**Input:** same shape as Tech Adoption, pre-scoped to AI tools and categories. Leave `trackedTool` empty and set an AI `trackedCategory` (for example `AI code assistant`) to catch every tool in it, or name one tool to follow a specific vendor. Both take exact catalog names from GET /api/v1/signals/technographic-tools. Firmographic filters apply as usual.\n\n**Output:** company-level leads with the adopted AI tool and the change date.\n\n**Use cases:**\n- *AI-adjacent services* — data prep, governance, security and training all become urgent once a model is live.\n- *Budget timing* — an AI line item signals discretionary spend that is already approved.\n- *Maturity segmentation* — first adoption vs. adding a second tool tells you which conversation to open.","operationId":"create_ai_adoption_signal_api_v1_signals_ai_adoption_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/TechAdoptionConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"AiAdoptionCreate","examples":[{"config":{"companyCountries":["FR","BE"],"companyEmployeeSizeRanges":["201-500","501-1000"],"getEmails":true,"trackedCategory":"AI code assistant"},"dailyLeadLimit":30,"name":"Companies adopting an AI code assistant (FR/BE, 201+)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies adopting an AI code assistant (FR/BE, 201+)","value":{"name":"Companies adopting an AI code assistant (FR/BE, 201+)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":30,"status":"active","config":{"trackedCategory":"AI code assistant","companyCountries":["FR","BE"],"companyEmployeeSizeRanges":["201-500","501-1000"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies adopting an AI code assistant (FR/BE, 201+)","status":"active","signalTypeId":"ai_adoption","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"trackedCategory":"AI code assistant","companyCountries":["FR","BE"],"companyEmployeeSizeRanges":["201-500","501-1000"],"getEmails":true},"dailyLeadLimit":30,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching company is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. The `job_offer_*` keys belong to the shared company-lead envelope and are always empty for this signal.","operationId":"ai_adoption_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies putting AI into production (FR/BE)","type":"ai_adoption","last_signal":"AI Adoption","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":"","technology":"OpenAI","technology_category":"AI","technology_change_date":"2026-07-29","competitor":""},"contact":"","company":{"name":"Verdano","website":"https://verdano.ai","linkedin_url":"https://www.linkedin.com/company/verdano","industry":"Software Development","location":"France","hq_country_code":"FR","hq_city":"","employee_count":"","employee_range":"11-50"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/company-followers":{"post":{"tags":["Signals"],"summary":"Create Company Followers signal","description":"Get the people who follow a company page — a warm audience that has already raised its hand for that company's content.\n\n**Input:** `linkedinCompanyUrls` (the pages to extract from), plus `targetPersonas` and the firmographic filters to keep only the followers matching your ICP. `targetCompanies` narrows further to followers who currently work at one of the companies you name (LinkedIn company URLs, up to 50) — use it to watch a page's audience for your own target accounts only.\n\n**Output:** person-level leads — name, title, LinkedIn URL, company.\n\n⚠️ **In `icp` mode (the default) this signal is quote-based and does not start on its own.** It can be `active` and still deliver nothing: extraction begins only once the follower volume has been priced and the quote accepted. Until then its responses carry a `QUOTE_REQUIRED` warning. Three ways to start it:\n- call `POST /api/v1/signals/{signal_id}/extraction/quote` (free), read `creditsQuoted`, then `POST .../extraction/accept` (holds the quoted credits; you are charged for the leads delivered);\n- or create it with `config.autoQuote: true` and a `config.maxCredits` budget: the quote is requested as soon as the signal is `active` and accepted for you when it costs no more than `maxCredits` — above that, it waits for your accept;\n- or accept the quote in the dashboard.\n\nFollow the extraction with `GET /api/v1/signals/{signal_id}/extraction`. In `count` mode (`extractionMode: \"count\"`, `extractionLimit` followers, unfiltered) there is no quote: activating the signal starts the extraction. `extractionLimit` must be at least 100: a lower value is refused with `422` and `error.code` `EXTRACTION_LIMIT_TOO_LOW`, on create and on a PATCH that sets it.\n\n**Company pages are checked.** A `linkedinCompanyUrls` entry that does not exist on LinkedIn is refused with `422` and `error.code` `COMPANY_PAGE_UNAVAILABLE` (`error.companyUrls` lists the pages), on create and on a PATCH that adds it — nothing is created or charged. A page we cannot verify at that moment is accepted with a `COMPANY_PAGE_UNVERIFIED` warning; if it turns out not to exist, its extraction stops without using credits and the signal carries a `COMPANY_PAGE_UNAVAILABLE` warning.\n\n**Use cases:**\n- *Competitor audience* — the people following a rival already care about the category.\n- *Event and community follow-up* — reach an audience that opted into a page.\n- *ICP validation* — who actually follows a company tells you who buys from it.","operationId":"create_company_followers_signal_api_v1_signals_company_followers_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyFollowersCreate"},"examples":{"example1":{"summary":"Followers of a competitor page (FR, HR personas)","value":{"name":"Followers of a competitor page (FR, HR personas)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"draft","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist"],"targetPersonas":["HR Director"],"locations":["France"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Followers of a competitor page (FR, HR personas)","status":"draft","signalTypeId":"company_followers","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist"],"targetPersonas":["HR Director"],"locations":["France"],"getEmails":true},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected. Person-level: `contact` always carries the person.","operationId":"company_followers_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyFollowersPayload","description":"Webhook payload for the company_followers signal.\n\nPerson-level: ``contact`` always carries the person. Same shape as the other\nperson-based payloads, but declared separately so the generated client names\nthe type after THIS signal — sharing WebhookPersonLeadPayload made a client\ncall it after the competitor-relationship signal.\n\nThe example is a real payload captured from the production push path on\n2026-07-30.","examples":[{"company":{"description":"","employee_count":"","employee_range":"501-1000","homepage_title":"","hq_city":"Lyon","hq_country_code":"FR","industry":"Manufacturing","linkedin_url":"https://www.linkedin.com/company/groupe-vallis","location":"Lyon, France","meta_description":"","name":"Groupe Vallis","tech_stack":"","website":"https://groupe-vallis.fr"},"contact":{"city":"Lyon","country_code":"FR","created_at":"2026-07-30T09:12:44+00:00","email":"","first_name":"Marc","last_name":"Delaunay","lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","linkedin_profile_url":"https://www.linkedin.com/in/marc-delaunay-demo","location":"Lyon, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"Directeur des Ressources Humaines"},"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","last_signal":"Company Follower","last_signal_date":"2026-07-30","name":"Followers of a competitor page (FR)","tracked_company":"","type":"company_followers"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Followers of a competitor page (FR)","type":"company_followers","last_signal":"Company Follower","last_signal_date":"2026-07-30","tracked_company":""},"contact":{"lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","created_at":"2026-07-30T09:12:44+00:00","first_name":"Marc","last_name":"Delaunay","email":"","phone":"","title":"Directeur des Ressources Humaines","location":"Lyon, France","country_code":"FR","city":"Lyon","linkedin_profile_url":"https://www.linkedin.com/in/marc-delaunay-demo","sales_navigator_profile_url":"","matched_persona":""},"company":{"name":"Groupe Vallis","website":"https://groupe-vallis.fr","linkedin_url":"https://www.linkedin.com/company/groupe-vallis","description":"","industry":"Manufacturing","location":"Lyon, France","hq_country_code":"FR","hq_city":"Lyon","employee_count":"","employee_range":"501-1000","tech_stack":"","homepage_title":"","meta_description":""}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyFollowersPayload","description":"Webhook payload for the company_followers signal.\n\nPerson-level: ``contact`` always carries the person. Same shape as the other\nperson-based payloads, but declared separately so the generated client names\nthe type after THIS signal — sharing WebhookPersonLeadPayload made a client\ncall it after the competitor-relationship signal.\n\nThe example is a real payload captured from the production push path on\n2026-07-30.","examples":[{"company":{"description":"","employee_count":"","employee_range":"501-1000","homepage_title":"","hq_city":"Lyon","hq_country_code":"FR","industry":"Manufacturing","linkedin_url":"https://www.linkedin.com/company/groupe-vallis","location":"Lyon, France","meta_description":"","name":"Groupe Vallis","tech_stack":"","website":"https://groupe-vallis.fr"},"contact":{"city":"Lyon","country_code":"FR","created_at":"2026-07-30T09:12:44+00:00","email":"","first_name":"Marc","last_name":"Delaunay","lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","linkedin_profile_url":"https://www.linkedin.com/in/marc-delaunay-demo","location":"Lyon, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"Directeur des Ressources Humaines"},"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","last_signal":"Company Follower","last_signal_date":"2026-07-30","name":"Followers of a competitor page (FR)","tracked_company":"","type":"company_followers"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/company-growth":{"post":{"tags":["Signals"],"summary":"Create Company Growth signal","description":"Find companies whose headcount is growing (or shrinking) by a chosen percentage, then surface the right decision-makers at each — typically executives who control budget or hiring.\n\n**Input:** your target geography and company profile (`locations`, `companySizeFilters`, `industryFilters`), the headcount growth band (`growthMin` and `growthMax` as signed percentages: negative values mean shrinking), which people to find at those companies (`enablePersonaLookup` flag + `targetPersonas` like \"Sales Director\"), and whether to enrich with emails/phones (`getEmails`, `getPhones`).\n\n**Output:** every new company matching your growth and ICP filters surfaces matched contacts to your `webhookUrl`. Each lead includes contact name, title, LinkedIn URL, company name/website, and matched persona. Email and phone are included only if enrichment is enabled. Persona targeting is mandatory—if `enablePersonaLookup` is false or `targetPersonas` is empty, the signal produces no leads.\n\n**Use cases:**\n- Scale-timing — growing companies need more seats and tools; pitch as they scale.\n- Restructuring plays — target shrinking companies with cost-optimisation offers.","operationId":"create_company_growth_signal_api_v1_signals_company_growth_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/CompanyGrowthConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":25},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"CompanyGrowthCreate","description":"Create a Company Growth signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500"],"enablePersonaLookup":true,"getEmails":true,"getPhones":false,"growthMax":100,"growthMin":20,"industryFilters":["Business Consulting and Services"],"locations":["France"],"personaExportMode":"top_ranked","targetPersonas":["Sales Director","Growth Director","Business Developer"]},"dailyLeadLimit":25,"name":"Fast-growing consultancies in France","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Fast-growing consultancies in France","value":{"name":"Fast-growing consultancies in France","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"locations":["France"],"companySizeFilters":["51-200","201-500"],"industryFilters":["Business Consulting and Services"],"growthMin":20,"growthMax":100,"enablePersonaLookup":true,"targetPersonas":["Sales Director","Growth Director","Business Developer"],"personaExportMode":"top_ranked","getEmails":true,"getPhones":false}}}}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Fast-growing consultancies in France","status":"active","signalTypeId":"company_growth","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"locations":["France"],"companySizeFilters":["51-200","201-500"],"industryFilters":["Business Consulting and Services"],"growthMin":20,"growthMax":100,"enablePersonaLookup":true,"targetPersonas":["Sales Director","Growth Director","Business Developer"],"getEmails":true,"getPhones":false},"dailyLeadLimit":25,"leadsToday":5,"leadsTotal":5,"duplicateHandling":"refuse","createdAt":"2026-07-03T09:00:00Z","updatedAt":"2026-07-03T09:00:00Z","lastLeadAt":"2026-07-03T09:12:00Z"}}}},"400":{"description":"Missing required config fields when creating as active","content":{"application/json":{"example":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["locations"],"missing_field_labels":["Locations"]}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_company_growth","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyGrowthPayload","description":"Webhook payload for the company_growth signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Sales Director","phone":"","sales_navigator_profile_url":"","title":"Sales Director"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"company_growth","last_signal_date":"2026-05-31","name":"FR companies growing +20%","tracked_company":"","type":"company_growth"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyGrowthPayload","description":"Webhook payload for the company_growth signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Sales Director","phone":"","sales_navigator_profile_url":"","title":"Sales Director"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"company_growth","last_signal_date":"2026-05-31","name":"FR companies growing +20%","tracked_company":"","type":"company_growth"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/company-news-watchlist":{"post":{"tags":["Signals"],"summary":"Create Company News Watchlist signal","description":"Know what just happened at the companies you sell to: funding, acquisitions and mergers, new locations, leadership changes, product launches, contracts and partnerships, layoffs and restructuring - and the trade shows they are about to exhibit at.\n\nUse it on the accounts you are working: a new site, a new leader or a deal is the moment priorities and suppliers get revisited, and a dated fact is a better opening line than a generic follow-up.\n\n**Input:** `companies` (a name, a domain, or a LinkedIn company URL per entry; a domain gives the most reliable match), `eventTypes` (empty = every type except `event_participation`, which you add by listing it), `maxEventAgeDays` (only deliver events from the last N days, default 90), `cadenceDays` (how often each company is checked, 14-90, default 30), plus optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`) and enrichment flags.\n\n**Output:** one company-level lead per event. The event travels on the `signal` block: `news_event_type` (the field to switch on), `news_event_date`, `news_headline`, `news_url` (the article it was checked against), `news_title` (the article's title) and `news_summary` (a short account of what the article says - what happened, who is involved, figures, stated plans - to ground an outreach message without opening the article). For `event_participation` (the company will exhibit or speak at an upcoming trade show or conference), `news_event_name` and `news_event_location` name the show and where it is held, and `news_event_date` is the day it starts - so you can book the meeting on the stand before the show, not after it.\n\n**What is checked before an event reaches you.** The article must be about THIS company (its website appears in the article; or its exact name together with its home city; or, for a name distinctive enough not to be shared, that exact name — a namesake elsewhere does not qualify). Companies are also followed under the brand names and websites they trade under, so news reported under a brand reaches whoever listed the legal entity behind it. The date is read from the article body and must fall inside your window (an old event re-published this week does not qualify; a trade show must still be ahead), and the event must be one of the types you asked for. The same event reported by several outlets is delivered once. `news_event_date` is given to the month (`YYYY-MM`) when the article does not state the day.\n\n**Persona targeting changes WHAT you receive; it does not add to it.** Turned on, the company-level lead is REPLACED by one lead per matching person at the company, so one event can deliver several payloads, or none. Persona leads are billed per person found.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response. Read what is watched with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Open with a fact, not a follow-up - a new branch, a new VP or a closed deal at an account you are working is the reason to call this week, and the date is on the lead.\n- Catch the reorganisation - an acquisition, a restructuring or a leadership change puts suppliers and tools back under review; hear it while the decision is still open.\n- Keep account plans current - push every verified event into the CRM record so the account owner sees what changed without reading the trade press.\n- Meet them on the show floor - when an account announces its booth at an upcoming trade show, book the meeting before the show fills their calendar.","operationId":"create_company_news_watchlist_signal_api_v1_signals_company_news_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/CompanyNewsWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"CompanyNewsWatchlistCreate","examples":[{"config":{"cadenceDays":30,"companies":["acmesupply.com",{"domain":"doctolib.fr","linkedinUrl":"https://www.linkedin.com/company/doctolib","name":"Doctolib"},"https://www.linkedin.com/company/lemlist"],"eventTypes":["funding","mergers_acquisitions","expansion","leadership_change"],"maxEventAgeDays":90},"dailyLeadLimit":20,"name":"News at my accounts","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"News at my accounts","value":{"name":"News at my accounts","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":20,"status":"active","config":{"companies":["acmesupply.com",{"name":"Doctolib","domain":"doctolib.fr","linkedinUrl":"https://www.linkedin.com/company/doctolib"},"https://www.linkedin.com/company/lemlist"],"eventTypes":["funding","mergers_acquisitions","expansion","leadership_change"],"maxEventAgeDays":90,"cadenceDays":30}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"News at my accounts","status":"active","signalTypeId":"company_news_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"eventTypes":["funding","mergers_acquisitions","expansion","leadership_change"],"maxEventAgeDays":90,"cadenceDays":30},"dailyLeadLimit":20,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per verified event at a watched company.","operationId":"company_news_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"news_event_type":{"type":"string","title":"News Event Type","description":"Event type: `funding`, `mergers_acquisitions`, `expansion`, `leadership_change`, `product_launch`, `contract_partnership`, `restructuring` or `event_participation` (the company will exhibit or speak at an upcoming trade show or conference). The field to switch on.","default":""},"news_event_label":{"type":"string","title":"News Event Label","description":"Human-readable event type","default":""},"news_event_date":{"type":"string","title":"News Event Date","description":"When the event happened, read from the article: YYYY-MM-DD, or YYYY-MM when the article only gives the month. For `event_participation` it is the date the trade show or conference starts, which is still ahead when the lead is delivered","default":""},"news_headline":{"type":"string","title":"News Headline","description":"One factual sentence describing the event","default":""},"news_url":{"type":"string","title":"News Url","description":"The article the event was verified against","default":""},"news_title":{"type":"string","title":"News Title","description":"The article's own title","default":""},"news_summary":{"type":"string","title":"News Summary","description":"A short summary (at most 1,500 characters) of what the article says about the event: what happened, who is involved, figures, and any stated reason or next step. Written when the event is verified, so you can ground an outreach message in the article without opening it. Empty for events verified before 2026-09-30","default":""},"news_event_name":{"type":"string","title":"News Event Name","description":"`event_participation` only: the trade show or conference, as the article names it (e.g. \"AHR Expo 2027\"). Empty for every other type","default":""},"news_event_location":{"type":"string","title":"News Event Location","description":"`event_participation` only: where the trade show or conference is held, when the article says. Empty for every other type","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompanyNewsSignal","description":"Signal block of a company_news_watchlist lead: the event that fired."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookCompanyNewsWatchlistPayload","description":"Webhook payload for company_news_watchlist.\n\nOne company-level lead per verified event at a watched company; ``contact``\nis ``\"\"`` unless persona targeting is enabled. The same event reported by\nseveral outlets is delivered once. The ``job_offer_*`` keys are always empty.","examples":[{"company":{"employee_count":"","employee_range":"201-500","hq_city":"Columbus","hq_country_code":"US","industry":"Wholesale","linkedin_url":"https://www.linkedin.com/company/acme-supply","location":"Columbus, Ohio, United States","name":"Acme Supply","website":"https://www.acmesupply.com"},"contact":"","signal":{"id":"c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Company News Watchlist","last_signal_date":"2026-09-25","matched_keywords":"","name":"News at my accounts","news_event_date":"2026-09-08","news_event_label":"New location or expansion","news_event_location":"","news_event_name":"","news_event_type":"expansion","news_headline":"Acme Supply opened a new 60,000 sq ft distribution center in Dallas, Texas.","news_summary":"Acme Supply opened a 60,000 sq ft distribution center in Dallas on September 8, its first in Texas. The site stocks about 12,000 products and adds 35 jobs. The company says it will cut delivery times to North Texas contractors to next day and plans a second Texas location in Houston in 2027.","news_title":"Acme Supply opens Dallas distribution center to serve North Texas contractors","news_url":"https://www.example-news.com/acme-supply-dallas","type":"company_news_watchlist"}}]},"example":{"signal":{"id":"c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f","name":"News at my accounts","type":"company_news_watchlist","last_signal":"Company News Watchlist","last_signal_date":"2026-09-25","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":"","news_event_type":"expansion","news_event_label":"New location or expansion","news_event_date":"2026-09-08","news_headline":"Acme Supply opened a new 60,000 sq ft distribution center in Dallas, Texas.","news_url":"https://www.example-news.com/acme-supply-dallas","news_title":"Acme Supply opens Dallas distribution center to serve North Texas contractors","news_summary":"Acme Supply opened a 60,000 sq ft distribution center in Dallas on September 8, its first in Texas. The site stocks about 12,000 products and adds 35 jobs. The company says it will cut delivery times to North Texas contractors to next day and plans a second Texas location in Houston in 2027.","news_event_name":"","news_event_location":""},"contact":"","company":{"name":"Acme Supply","website":"https://www.acmesupply.com","linkedin_url":"https://www.linkedin.com/company/acme-supply","industry":"Wholesale","location":"Columbus, Ohio, United States","hq_country_code":"US","hq_city":"Columbus","employee_count":"","employee_range":"201-500"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"news_event_type":{"type":"string","title":"News Event Type","description":"Event type: `funding`, `mergers_acquisitions`, `expansion`, `leadership_change`, `product_launch`, `contract_partnership`, `restructuring` or `event_participation` (the company will exhibit or speak at an upcoming trade show or conference). The field to switch on.","default":""},"news_event_label":{"type":"string","title":"News Event Label","description":"Human-readable event type","default":""},"news_event_date":{"type":"string","title":"News Event Date","description":"When the event happened, read from the article: YYYY-MM-DD, or YYYY-MM when the article only gives the month. For `event_participation` it is the date the trade show or conference starts, which is still ahead when the lead is delivered","default":""},"news_headline":{"type":"string","title":"News Headline","description":"One factual sentence describing the event","default":""},"news_url":{"type":"string","title":"News Url","description":"The article the event was verified against","default":""},"news_title":{"type":"string","title":"News Title","description":"The article's own title","default":""},"news_summary":{"type":"string","title":"News Summary","description":"A short summary (at most 1,500 characters) of what the article says about the event: what happened, who is involved, figures, and any stated reason or next step. Written when the event is verified, so you can ground an outreach message in the article without opening it. Empty for events verified before 2026-09-30","default":""},"news_event_name":{"type":"string","title":"News Event Name","description":"`event_participation` only: the trade show or conference, as the article names it (e.g. \"AHR Expo 2027\"). Empty for every other type","default":""},"news_event_location":{"type":"string","title":"News Event Location","description":"`event_participation` only: where the trade show or conference is held, when the article says. Empty for every other type","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompanyNewsSignal","description":"Signal block of a company_news_watchlist lead: the event that fired."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookCompanyNewsWatchlistPayload","description":"Webhook payload for company_news_watchlist.\n\nOne company-level lead per verified event at a watched company; ``contact``\nis ``\"\"`` unless persona targeting is enabled. The same event reported by\nseveral outlets is delivered once. The ``job_offer_*`` keys are always empty.","examples":[{"company":{"employee_count":"","employee_range":"201-500","hq_city":"Columbus","hq_country_code":"US","industry":"Wholesale","linkedin_url":"https://www.linkedin.com/company/acme-supply","location":"Columbus, Ohio, United States","name":"Acme Supply","website":"https://www.acmesupply.com"},"contact":"","signal":{"id":"c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Company News Watchlist","last_signal_date":"2026-09-25","matched_keywords":"","name":"News at my accounts","news_event_date":"2026-09-08","news_event_label":"New location or expansion","news_event_location":"","news_event_name":"","news_event_type":"expansion","news_headline":"Acme Supply opened a new 60,000 sq ft distribution center in Dallas, Texas.","news_summary":"Acme Supply opened a 60,000 sq ft distribution center in Dallas on September 8, its first in Texas. The site stocks about 12,000 products and adds 35 jobs. The company says it will cut delivery times to North Texas contractors to next day and plans a second Texas location in Houston in 2027.","news_title":"Acme Supply opens Dallas distribution center to serve North Texas contractors","news_url":"https://www.example-news.com/acme-supply-dallas","type":"company_news_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/company-page-engagement":{"post":{"tags":["Signals"],"summary":"Create Company Page Engagement signal","description":"Find prospects who actively engage with posts from specific company pages—a strong signal of intent in those business areas.\n\n**Input:** one or more target LinkedIn company page URLs (`linkedinCompanyUrls`), plus optional ICP filters (`targetPersonas`, `companySizeFilters`, `locations`, `industryFilters`, `excludedTitles`, etc.) and engagement settings (`engagementTypes`—defaults to likes/comments; `minEngagement`—minimum post reactions to trigger a lead; `postedLimit`—time window, default \"week\").\n\n**Output:** every person who engages with posts from those company pages, matching your engagement and filter config, is pushed to your `webhookUrl` as an enriched lead; those not matching are filtered out. Engagement defaults to people who liked OR commented (combine values: use `[\"both\"]` for intersection—highest intent).\n\n**Use cases:**\n- Competitor-audience capture — reach people engaging with a competitor's company posts.\n- Industry-intent — engagers on industry content signal active category interest.","operationId":"create_company_post_reactions_signal_api_v1_signals_company_page_engagement_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/CompanyPostReactionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"CompanyPostReactionsCreate","description":"Create a Company Page Engagement signal.","examples":[{"config":{"companySizeFilters":[],"customPersonaTitles":[],"detectTechnologies":false,"engagementTypes":["likes","comments"],"excludedCompanySizeFilters":[],"excludedCompanyUrls":[],"excludedIndustryFilters":[],"excludedLocations":[],"excludedTitles":[],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"industryFilters":[],"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist"],"locations":[],"maxPosts":0,"minEngagement":5,"postedLimit":"week","targetPersonas":[]},"dailyLeadLimit":50,"name":"Company page reactions","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Company page reactions","value":{"name":"Company page reactions","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist"],"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanySizeFilters":[],"excludedTitles":[],"excludedCompanyUrls":[],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Company page reactions","status":"active","signalTypeId":"company_post_reactions","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist"],"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanySizeFilters":[],"excludedTitles":[],"excludedCompanyUrls":[],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config (Companies to Monitor), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (Companies to Monitor)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["linkedin_company_urls"],"missing_field_labels":["Companies to Monitor"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"company_page_engagement_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company page URL","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL that was engaged with","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment (if engagement_type is comment)","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompanyPageEngagementSignal","description":"Signal info for company page engagement signals (company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyPageEngagementPayload","description":"Webhook payload for company page engagement signals (company_post_reactions).","examples":[{"company":{"linkedin_url":"https://linkedin.com/company/techcorp","name":"Tech Corp","website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-02-24T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://linkedin.com/in/mariedupont","location":"Paris, France","matched_persona":"VP of Engineering","phone":"+33612345678","sales_navigator_profile_url":"https://linkedin.com/sales/lead/ACoAAA...","title":"VP Engineering"},"signal":{"engagement_type":"like","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Company Post Reactions","last_signal_date":"2026-02-24","mention_content":"","name":"Company Page Reactions","post_author_first_name":"Claire","post_author_last_name":"Lefevre","post_content":"We just closed our Series B! Read more about our next chapter.","post_date":"2026-02-23","post_url":"https://linkedin.com/feed/update/urn:li:activity:456789","tracked_company":"https://linkedin.com/company/competitor","type":"company_post_reactions"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company page URL","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL that was engaged with","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment (if engagement_type is comment)","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompanyPageEngagementSignal","description":"Signal info for company page engagement signals (company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyPageEngagementPayload","description":"Webhook payload for company page engagement signals (company_post_reactions).","examples":[{"company":{"linkedin_url":"https://linkedin.com/company/techcorp","name":"Tech Corp","website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-02-24T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://linkedin.com/in/mariedupont","location":"Paris, France","matched_persona":"VP of Engineering","phone":"+33612345678","sales_navigator_profile_url":"https://linkedin.com/sales/lead/ACoAAA...","title":"VP Engineering"},"signal":{"engagement_type":"like","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Company Post Reactions","last_signal_date":"2026-02-24","mention_content":"","name":"Company Page Reactions","post_author_first_name":"Claire","post_author_last_name":"Lefevre","post_content":"We just closed our Series B! Read more about our next chapter.","post_date":"2026-02-23","post_url":"https://linkedin.com/feed/update/urn:li:activity:456789","tracked_company":"https://linkedin.com/company/competitor","type":"company_post_reactions"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/company-registration":{"post":{"tags":["Signals"],"summary":"Create Company Registration signal","description":"Discover newly registered French companies matching your industry and geography filters — automatically surface the founders and decision-makers behind fresh companies as they register.\n\n**Input:** French SIRENE filters (`nafCodes` for industry via NAF activity codes, `departmentCodes` and/or `regionCodes` for geography, `legalForms` for legal status such as SAS/SARL, `employeeSizeCodes` for headcount range), plus optional persona targeting (`enablePersonaTargeting` + `targetPersonas` to find founders, CEOs, or specific roles).\n\n**Output:** Each new company matching your filters is delivered to your `webhookUrl` as a company-level lead with SIRENE registration metadata (company name, SIREN identifier, creation date, location, activity code, legal form, employee range). When persona targeting is enabled, the founders/decision-makers behind the company are resolved and delivered as per-person leads instead of a separate company lead — each person lead carries the same company registration data.\n\n**Use cases:**\n- First-mover outreach — reach brand-new companies before competitors and become their first vendor.\n- Founder tooling — pitch startup / founder solutions at day zero.","operationId":"create_company_registration_signal_api_v1_signals_company_registration_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/CompanyRegistrationConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"CompanyRegistrationCreate","description":"Create a Company Registration signal.","examples":[{"config":{"customPersonaTitles":["Founder","Co-Founder"],"departmentCodes":["75","92","93","94"],"detectTechnologies":false,"employeeSizeCodes":[],"enablePersonaTargeting":true,"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"legalForms":["5710"],"nafCodes":["62.01Z"],"personaExportMode":"top_ranked","personaLocations":[],"regionCodes":["11"],"targetPersonas":["CEO","CTO"]},"dailyLeadLimit":50,"name":"New SAS in Île-de-France","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"New SAS in Île-de-France","value":{"name":"New SAS in Île-de-France","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"nafCodes":["62.01Z"],"departmentCodes":["75","92","93","94"],"regionCodes":["11"],"legalForms":["5710"],"employeeSizeCodes":[],"enablePersonaTargeting":true,"targetPersonas":["CEO","CTO"],"customPersonaTitles":["Founder","Co-Founder"],"personaExportMode":"top_ranked","personaLocations":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"New SAS in Île-de-France","status":"active","signalTypeId":"company_registration","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"nafCodes":["62.01Z"],"departmentCodes":["75","92","93","94"],"regionCodes":["11"],"legalForms":["5710"],"employeeSizeCodes":[],"enablePersonaTargeting":true,"targetPersonas":["CEO","CTO"],"customPersonaTitles":["Founder","Co-Founder"],"personaExportMode":"top_ranked","personaLocations":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching job is found. `contact` is null unless persona targeting is enabled.","operationId":"job_lead_webhook_company_registration","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"registration_number":{"type":"string","title":"Registration Number","description":"SIREN of the newly registered company (9 digits)","default":""},"registration_date":{"type":"string","title":"Registration Date","description":"Date the company was registered (`2026-05-28`)","default":""},"legal_form":{"type":"string","title":"Legal Form","description":"Legal form of the company (e.g. SAS, SARL)","default":""},"activity_code":{"type":"string","title":"Activity Code","description":"NAF / APE activity code (e.g. `62.01Z`)","default":""},"activity_description":{"type":"string","title":"Activity Description","description":"Label of the NAF / APE activity code","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompanyRegistrationSignal","description":"Signal info for company_registration: the newly registered French company."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyRegistrationPayload","description":"Webhook payload for the company_registration signal (company-only unless\npersona targeting resolves the founders/decision-makers).","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":3,"employee_range":"1-10","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"E-Commerce Retail","linkedin_url":"https://linkedin.com/company/techcorp","location":"PARIS, 75","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Founder","phone":"","sales_navigator_profile_url":"","title":"Founder"},"signal":{"activity_code":"62.01Z","activity_description":"Programmation informatique","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Company Registration","last_signal_date":"2026-05-31","legal_form":"SAS","name":"New French tech companies","registration_date":"2026-05-28","registration_number":"552100554","tracked_company":"","type":"company_registration"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"registration_number":{"type":"string","title":"Registration Number","description":"SIREN of the newly registered company (9 digits)","default":""},"registration_date":{"type":"string","title":"Registration Date","description":"Date the company was registered (`2026-05-28`)","default":""},"legal_form":{"type":"string","title":"Legal Form","description":"Legal form of the company (e.g. SAS, SARL)","default":""},"activity_code":{"type":"string","title":"Activity Code","description":"NAF / APE activity code (e.g. `62.01Z`)","default":""},"activity_description":{"type":"string","title":"Activity Description","description":"Label of the NAF / APE activity code","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompanyRegistrationSignal","description":"Signal info for company_registration: the newly registered French company."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompanyRegistrationPayload","description":"Webhook payload for the company_registration signal (company-only unless\npersona targeting resolves the founders/decision-makers).","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":3,"employee_range":"1-10","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"E-Commerce Retail","linkedin_url":"https://linkedin.com/company/techcorp","location":"PARIS, 75","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Founder","phone":"","sales_navigator_profile_url":"","title":"Founder"},"signal":{"activity_code":"62.01Z","activity_description":"Programmation informatique","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Company Registration","last_signal_date":"2026-05-31","legal_form":"SAS","name":"New French tech companies","registration_date":"2026-05-28","registration_number":"552100554","tracked_company":"","type":"company_registration"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/company-types":{"get":{"tags":["Signals"],"summary":"List company type filter values","description":"Company-type vocabulary for `companyTypeFilters`.\n\nA short closed list, unlike the 453-value industry vocabulary, so it is\nreturned whole with no search or paging.","operationId":"list_company_types_api_v1_signals_company_types_get","responses":{"200":{"description":"Every value accepted by companyTypeFilters.","content":{"application/json":{"schema":{"properties":{"total":{"type":"integer","title":"Total","description":"How many values exist."},"companyTypes":{"items":{"type":"string"},"type":"array","title":"Companytypes","description":"Every value accepted by companyTypeFilters."}},"type":"object","required":["total","companyTypes"],"title":"CompanyTypesResponse","description":"The closed vocabulary accepted by `companyTypeFilters`."},"examples":{"full_list":{"summary":"The complete vocabulary","value":{"total":8,"companyTypes":["Educational Institution","Government Agency","Nonprofit","Partnership","Privately Held","Public Company","Self-Employed","Sole Proprietorship"]}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/competitor-connections":{"post":{"tags":["Signals"],"summary":"Create Competitor Connections signal","description":"Identify every new 1st-degree connection to your competitors' sales and business teams — typically the prospects and customers your competitors are actively engaging, and often the highest-intent leads in your market. Reach them the moment they enter your competitors' network within your target market.\n\n**Input:** one or more competitor LinkedIn company URLs (`linkedinCompanyUrls`), optional LinkedIn profile URLs to track directly (`linkedinProfileUrls` — each named person produces leads only once they have accepted our connection request; a `PATCH` with a new list starts watching added people and stops watching removed ones); optional enrichment toggles (`getEmails`, `getPhones`, `getSireneData`, `detectTechnologies`, `getHomepageContent`); optional persona targeting (`targetPersonas`, `customPersonaTitles`); optional ICP filters (`companySizeFilters`, `locations`, `industryFilters`, `excludedLocations`, `excludedTitles`, `excludedCompanyUrls`).\n\n**Output:** every new 1st-degree connection detected at a tracked competitor, if it matches your filters (persona + ICP), is pushed to your `webhookUrl` as an enriched person lead; non-matching connections are filtered out. Each webhook payload includes the contact (name, email if enriched, phone if enriched, title, location, LinkedIn profile URL, matched persona), their employer (company name, website, LinkedIn URL, plus detected tech stack and homepage content when those enrichments are enabled), the competitor company URL where the 1st-degree connection was detected (`signal.tracked_company`, empty when you only watch individual profiles), and the LinkedIn URL of the watched person the lead connected with (`signal.tracked_contact`) — so a signal watching several people tells you which one produced each lead.\n\n**Use cases:**\n- Competitor displacement — these people are already evaluating solutions in your category; trigger a differentiation-led outbound sequence the day they connect, while intent is highest.\n- CRM enrichment & routing — push the enriched contact + firmographics (size, industry, tech stack) into your CRM to auto-score and route to the right rep.\n- Account-based triggers — when several people at one target account connect with a competitor, fire an ABM play (ads + SDR + exec outreach) on that account.\n- Win-back watch — cross-reference against your own customer list to spot accounts drifting toward a competitor.","operationId":"create_competitor_connections_signal","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitorRelationshipCreate"},"examples":{"example1":{"summary":"Tech competitors in France","value":{"name":"Tech competitors in France","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Sales Director","Marketing Director"],"customPersonaTitles":["VP of Growth","Chief Revenue Officer"],"locations":["France"],"excludedLocations":["Paris"],"industryFilters":["Technology, Information and Internet","Software Development"],"excludedIndustryFilters":["Financial Services"],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":["Intern","Junior"],"excludedCompanyUrls":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Tech competitors in France","status":"active","signalTypeId":"competitor_relationship_monitoring","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Sales Director","Marketing Director"],"customPersonaTitles":["VP of Growth","Chief Revenue Officer"],"locations":["France"],"excludedLocations":["Paris"],"industryFilters":["Technology, Information and Internet","Software Development"],"excludedIndustryFilters":["Financial Services"],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":["Intern","Junior"],"excludedCompanyUrls":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{"allowUnknownCompanySize":false},"warnings":[{"code":"UNKNOWN_SIZE_NOT_ACCEPTED","severity":"info","field":"allowUnknownCompanySize","message":"Companies whose size cannot be determined are accepted only when the size selection includes a band under 51 employees (\"Self-employed\", \"1-10\", \"11-50\"). This selection does not, so such companies are not delivered.","values":[]}]}}}},"400":{"description":"Invalid request: missing required config (Companies to Monitor), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (Companies to Monitor)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["linkedin_company_urls"],"missing_field_labels":["Companies to Monitor"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_competitor_relationships","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the tracked company (an entry of ``linkedinCompanyUrls``) whose employee the lead connected with. Empty when the signal only watches individual profiles (``linkedinProfileUrls``).","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person the lead connected with: one of your ``linkedinProfileUrls``, or the tracked company's employee whose network surfaced the lead. Use it to tell which watched profile produced each lead when one signal watches several people.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompetitorConnectionSignal","description":"Signal info for the competitor connection signals\n(competitor_relationship_monitoring, competitor_customer_care).\n\n``tracked_contact`` names the watched person whose network the lead just\njoined, so a signal watching several people tells you which one produced\neach lead."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorRelationshipPayload","description":"Webhook payload for the competitor_relationship_monitoring signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Relationship Monitoring","last_signal_date":"2026-05-31","name":"Tech competitors in France","tracked_company":"https://www.linkedin.com/company/competitor-ag/","tracked_contact":"https://www.linkedin.com/in/julien-moreau-competitor/","type":"competitor_relationship_monitoring"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the tracked company (an entry of ``linkedinCompanyUrls``) whose employee the lead connected with. Empty when the signal only watches individual profiles (``linkedinProfileUrls``).","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person the lead connected with: one of your ``linkedinProfileUrls``, or the tracked company's employee whose network surfaced the lead. Use it to tell which watched profile produced each lead when one signal watches several people.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompetitorConnectionSignal","description":"Signal info for the competitor connection signals\n(competitor_relationship_monitoring, competitor_customer_care).\n\n``tracked_contact`` names the watched person whose network the lead just\njoined, so a signal watching several people tells you which one produced\neach lead."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorRelationshipPayload","description":"Webhook payload for the competitor_relationship_monitoring signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Relationship Monitoring","last_signal_date":"2026-05-31","name":"Tech competitors in France","tracked_company":"https://www.linkedin.com/company/competitor-ag/","tracked_contact":"https://www.linkedin.com/in/julien-moreau-competitor/","type":"competitor_relationship_monitoring"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/competitor-customer-care":{"post":{"tags":["Signals"],"summary":"Create Competitor Customer Care Connections signal","description":"Identify people newly connecting with your competitors' customer success and support teams — a strong signal they are becoming (or already are) that competitor's customers.\n\n**Input:** one or more competitor LinkedIn company URLs (`linkedinCompanyUrls`) and/or the LinkedIn profile URLs of specific care-team members to watch (`linkedinProfileUrls`, e.g. `https://www.linkedin.com/in/marie-dupont`) — at least one of the two is required to activate. A person named in `linkedinProfileUrls` produces leads only once they have accepted our connection request, which can take days; someone who never accepts produces none. On a live signal, `PATCH /api/v1/signals/{signal_id}` with a new `linkedinProfileUrls` list starts watching the people you added and stops watching the people you removed (send the full list you want). Plus optional filters (persona/ICP: `targetPersonas`, `customPersonaTitles`, `companySizeFilters`, `locations`, `excludedLocations`, `industryFilters`, `excludedCompanySizeFilters`, `excludedTitles`, `excludedCompanyUrls`), enrichment options (`getEmails`, `getPhones`, `detectTechnologies`), and your `webhookUrl` and `dailyLeadLimit`.\n\n**Output:** every new 1st-degree connection to the monitored competitor's care team, matching your config filters, is pushed to your `webhookUrl` as an enriched lead with contact details (name, title, location, email/phone if enabled, LinkedIn profile) and company info, plus the monitored competitor (`signal.tracked_company`) and the care-team member the lead connected with (`signal.tracked_contact`); non-matching connections are filtered out.\n\n**Use cases:**\n- Steal-the-customer outreach — these people are (becoming) a competitor's customers; pitch a migration with a switch offer.\n- Renewal-timing plays — sequence them toward likely contract-renewal windows.\n- Competitive intelligence — map who your competitors are onboarding to gauge their momentum.","operationId":"create_competitor_customer_care_signal_api_v1_signals_competitor_customer_care_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/LinkedInConnectionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"CompetitorCustomerCareCreate","description":"Create a Competitor Customer Care Connections signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500","501-1000"],"customPersonaTitles":["VP of Operations"],"detectTechnologies":false,"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedCompanyUrls":[],"excludedIndustryFilters":[],"excludedLocations":[],"excludedTitles":["Intern"],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"industryFilters":["Software Development"],"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"locations":["France"],"targetPersonas":["Operations Director","Head of Revenue"]},"dailyLeadLimit":50,"name":"Customers of our top competitors","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Customers of our top competitors","value":{"name":"Customers of our top competitors","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Operations Director","Head of Revenue"],"customPersonaTitles":["VP of Operations"],"locations":["France"],"excludedLocations":[],"industryFilters":["Software Development"],"excludedIndustryFilters":[],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":["Intern"],"excludedCompanyUrls":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Customers of our top competitors","status":"active","signalTypeId":"competitor_customer_care","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Operations Director","Head of Revenue"],"customPersonaTitles":["VP of Operations"],"locations":["France"],"excludedLocations":[],"industryFilters":["Software Development"],"excludedIndustryFilters":[],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":["Intern"],"excludedCompanyUrls":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{"allowUnknownCompanySize":false},"warnings":[{"code":"UNKNOWN_SIZE_NOT_ACCEPTED","severity":"info","field":"allowUnknownCompanySize","message":"Companies whose size cannot be determined are accepted only when the size selection includes a band under 51 employees (\"Self-employed\", \"1-10\", \"11-50\"). This selection does not, so such companies are not delivered.","values":[]}]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_competitor_customer_care","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the tracked company (an entry of ``linkedinCompanyUrls``) whose employee the lead connected with. Empty when the signal only watches individual profiles (``linkedinProfileUrls``).","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person the lead connected with: one of your ``linkedinProfileUrls``, or the tracked company's employee whose network surfaced the lead. Use it to tell which watched profile produced each lead when one signal watches several people.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompetitorConnectionSignal","description":"Signal info for the competitor connection signals\n(competitor_relationship_monitoring, competitor_customer_care).\n\n``tracked_contact`` names the watched person whose network the lead just\njoined, so a signal watching several people tells you which one produced\neach lead."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorCustomerCarePayload","description":"Webhook payload for the competitor_customer_care signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"Talent Partner"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Customer Care","last_signal_date":"2026-05-31","name":"Competitor's customers","tracked_company":"https://www.linkedin.com/company/competitor-ag/","tracked_contact":"https://www.linkedin.com/in/claire-martin-support/","type":"competitor_customer_care"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the tracked company (an entry of ``linkedinCompanyUrls``) whose employee the lead connected with. Empty when the signal only watches individual profiles (``linkedinProfileUrls``).","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person the lead connected with: one of your ``linkedinProfileUrls``, or the tracked company's employee whose network surfaced the lead. Use it to tell which watched profile produced each lead when one signal watches several people.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompetitorConnectionSignal","description":"Signal info for the competitor connection signals\n(competitor_relationship_monitoring, competitor_customer_care).\n\n``tracked_contact`` names the watched person whose network the lead just\njoined, so a signal watching several people tells you which one produced\neach lead."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorCustomerCarePayload","description":"Webhook payload for the competitor_customer_care signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"Talent Partner"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Customer Care","last_signal_date":"2026-05-31","name":"Competitor's customers","tracked_company":"https://www.linkedin.com/company/competitor-ag/","tracked_contact":"https://www.linkedin.com/in/claire-martin-support/","type":"competitor_customer_care"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/competitor-customers":{"post":{"tags":["Signals"],"summary":"Create Competitor Customers signal","description":"Get the companies currently RUNNING a competitor's tool — a standing list of displacement targets rather than a change event.\n\n**Input:** `trackedTool` (the competitor) or `trackedCategory`, plus the firmographic filters. `excludeDomains` removes domains you already work with.\n\n**Output:** company-level leads with the tool in use. Unlike Tech Adoption and Displacement, these are steady-state users, not a dated change — so pace delivery with `dailyLeadLimit` rather than expecting bursts.\n\n**Use cases:**\n- *Displacement campaign* — a target list built on verified usage, not guesses.\n- *Battlecard targeting* — segment by competitor to send the right comparison.\n- *Territory mapping* — see where a rival is entrenched before planning a push.","operationId":"create_competitor_customer_signal_api_v1_signals_competitor_customers_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/TechAdoptionConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"CompetitorCustomerCreate","examples":[{"config":{"companyCountries":["FR"],"companyEmployeeSizeRanges":["51-200","201-500"],"excludeDomains":["lemlist.com"],"trackedTool":"Pipedrive"},"dailyLeadLimit":40,"name":"Companies running a competitor CRM (FR, 51-500)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies running a competitor CRM (FR, 51-500)","value":{"name":"Companies running a competitor CRM (FR, 51-500)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":40,"status":"active","config":{"trackedTool":"Pipedrive","companyCountries":["FR"],"companyEmployeeSizeRanges":["51-200","201-500"],"excludeDomains":["lemlist.com"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies running a competitor CRM (FR, 51-500)","status":"active","signalTypeId":"competitor_customer","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"trackedTool":"Pipedrive","companyCountries":["FR"],"companyEmployeeSizeRanges":["51-200","201-500"],"excludeDomains":["lemlist.com"]},"dailyLeadLimit":40,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching company is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. The `job_offer_*` keys belong to the shared company-lead envelope and are always empty for this signal.","operationId":"competitor_customer_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies running a competitor CRM (FR)","type":"competitor_customer","last_signal":"Competitor Customer","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":"","technology":"Pipedrive","technology_category":"","technology_change_date":"","competitor":"Pipedrive"},"contact":"","company":{"name":"Brightpath Retail","website":"https://brightpath-retail.com","linkedin_url":"https://www.linkedin.com/company/brightpath-retail","industry":"Retail","location":"France","hq_country_code":"FR","hq_city":"","employee_count":"","employee_range":"501-1000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/competitor-relationships":{"post":{"tags":["Signals"],"summary":"Create Competitor Connections signal (deprecated — use /signals/competitor-connections)","description":"**Deprecated.** Renamed to `POST /api/v1/signals/competitor-connections` — same request body, same response, same webhook. Kept working indefinitely for existing integrations; build new ones against the new path.","operationId":"create_competitor_relationship_signal_deprecated","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitorRelationshipCreate"},"examples":{"example1":{"summary":"Tech competitors in France","value":{"name":"Tech competitors in France","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Sales Director","Marketing Director"],"customPersonaTitles":["VP of Growth","Chief Revenue Officer"],"locations":["France"],"excludedLocations":["Paris"],"industryFilters":["Technology, Information and Internet","Software Development"],"excludedIndustryFilters":["Financial Services"],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":["Intern","Junior"],"excludedCompanyUrls":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Tech competitors in France","status":"active","signalTypeId":"competitor_relationship_monitoring","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Sales Director","Marketing Director"],"customPersonaTitles":["VP of Growth","Chief Revenue Officer"],"locations":["France"],"excludedLocations":["Paris"],"industryFilters":["Technology, Information and Internet","Software Development"],"excludedIndustryFilters":["Financial Services"],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":["Intern","Junior"],"excludedCompanyUrls":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{"allowUnknownCompanySize":false},"warnings":[{"code":"UNKNOWN_SIZE_NOT_ACCEPTED","severity":"info","field":"allowUnknownCompanySize","message":"Companies whose size cannot be determined are accepted only when the size selection includes a band under 51 employees (\"Self-employed\", \"1-10\", \"11-50\"). This selection does not, so such companies are not delivered.","values":[]}]}}}},"400":{"description":"Invalid request: missing required config (Companies to Monitor), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (Companies to Monitor)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["linkedin_company_urls"],"missing_field_labels":["Companies to Monitor"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_competitor_relationships_deprecated_alias","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the tracked company (an entry of ``linkedinCompanyUrls``) whose employee the lead connected with. Empty when the signal only watches individual profiles (``linkedinProfileUrls``).","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person the lead connected with: one of your ``linkedinProfileUrls``, or the tracked company's employee whose network surfaced the lead. Use it to tell which watched profile produced each lead when one signal watches several people.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompetitorConnectionSignal","description":"Signal info for the competitor connection signals\n(competitor_relationship_monitoring, competitor_customer_care).\n\n``tracked_contact`` names the watched person whose network the lead just\njoined, so a signal watching several people tells you which one produced\neach lead."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorRelationshipPayload","description":"Webhook payload for the competitor_relationship_monitoring signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Relationship Monitoring","last_signal_date":"2026-05-31","name":"Tech competitors in France","tracked_company":"https://www.linkedin.com/company/competitor-ag/","tracked_contact":"https://www.linkedin.com/in/julien-moreau-competitor/","type":"competitor_relationship_monitoring"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the tracked company (an entry of ``linkedinCompanyUrls``) whose employee the lead connected with. Empty when the signal only watches individual profiles (``linkedinProfileUrls``).","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person the lead connected with: one of your ``linkedinProfileUrls``, or the tracked company's employee whose network surfaced the lead. Use it to tell which watched profile produced each lead when one signal watches several people.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookCompetitorConnectionSignal","description":"Signal info for the competitor connection signals\n(competitor_relationship_monitoring, competitor_customer_care).\n\n``tracked_contact`` names the watched person whose network the lead just\njoined, so a signal watching several people tells you which one produced\neach lead."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorRelationshipPayload","description":"Webhook payload for the competitor_relationship_monitoring signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Relationship Monitoring","last_signal_date":"2026-05-31","name":"Tech competitors in France","tracked_company":"https://www.linkedin.com/company/competitor-ag/","tracked_contact":"https://www.linkedin.com/in/julien-moreau-competitor/","type":"competitor_relationship_monitoring"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"deprecated":true,"security":[{"BearerAuth":[]}]}},"/api/v1/signals/competitor-social-reactions":{"post":{"tags":["Signals"],"summary":"Create Competitor Social Reactions signal","description":"Discover prospects your competitors' GTM teams are actively paying attention to by monitoring the posts their sales, customer success, business development, operations, and founder employees engage with.\n\n**Input:** competitor LinkedIn company URLs (`linkedinCompanyUrls`, up to 50), time window for engagement detection (`postedLimit`), engagement types to surface as leads (`engagementTypes` — e.g. `[\"poster\"]` for post authors only, or `[\"likes\", \"comments\"]` for engagers only; defaults to `[\"poster\", \"likes\", \"comments\"]`), minimum engagement threshold (`minEngagement`), and standard ICP filters (`targetPersonas`, `companySizeFilters`, `locations`, etc.).\n\n**Output:** each surfaced post creates one or more leads (the post author plus engagers matching your `engagementTypes` config). Every lead is pushed to your `webhookUrl` as it is detected, filtered by your persona and ICP config. The webhook payload includes `signal.tracked_company` (which competitor URL surfaced it), `signal.tracked_contact` (the LinkedIn URL of the specific competitor employee whose like/comment exposed the post), and `signal.post_url` with engagement details — so your team can trace each lead back to a named buyer at the competitor and frame outreach accordingly.\n\n**Use cases:**\n- Warm-intent outreach — engagers are actively interested in your category; open with the exact topic they engaged on.\n- Retargeting audiences — build a lookalike / ad-retargeting list from the engagers.\n- Author-first prospecting — the post authors are influential voices in the competitor's orbit and high-value contacts.","operationId":"create_competitor_social_reactions_signal_api_v1_signals_competitor_social_reactions_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/CompetitorSocialReactionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"CompetitorSocialReactionsCreate","description":"Create a Competitor Social Reactions signal.","examples":[{"config":{"companySizeFilters":[],"customPersonaTitles":[],"engagementTypes":["likes","comments"],"excludedCompanySizeFilters":[],"excludedCompanyUrls":[],"excludedIndustryFilters":[],"excludedLocations":[],"excludedTitles":[],"getEmails":true,"getPhones":false,"industryFilters":[],"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist/","https://www.linkedin.com/company/salesloft/","https://www.linkedin.com/company/outreachio/"],"locations":[],"maxPosts":0,"minEngagement":5,"postedLimit":"week","targetPersonas":[]},"dailyLeadLimit":50,"name":"What lemlist's GTM team is reading","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"What lemlist's GTM team is reading","value":{"name":"What lemlist's GTM team is reading","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist/","https://www.linkedin.com/company/salesloft/","https://www.linkedin.com/company/outreachio/"],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"],"getEmails":true,"getPhones":false,"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanySizeFilters":[],"excludedTitles":[],"excludedCompanyUrls":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"What lemlist's GTM team is reading","status":"active","signalTypeId":"competitor_social_reactions","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist/","https://www.linkedin.com/company/salesloft/","https://www.linkedin.com/company/outreachio/"],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"],"getEmails":true,"getPhones":false,"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanySizeFilters":[],"excludedTitles":[],"excludedCompanyUrls":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new competitor-social-reaction lead is detected. ``signal.tracked_company`` is the competitor URL (from ``linkedinCompanyUrls``) that surfaced the lead. ``signal.tracked_contact`` is the LinkedIn URL of the specific employee at that competitor whose reaction got the post on our radar.","operationId":"competitor_social_lead_webhook_competitor_social_reactions","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the contact whose engagement surfaced this post to us. For ``competitor_social_reactions``, this is the employee at the tracked competitor (one of the URLs in ``linkedinCompanyUrls``) whose like/comment bubbled the post up — use it to trace the lead back to a specific named buyer at the competitor. For social_mentions / social_reactions, this is the post author.","default":""},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the company whose engagement surfaced this lead. For ``competitor_social_reactions``, this is the entry from ``linkedinCompanyUrls`` that the ``tracked_contact`` works at. For other social signals, the company the system was monitoring.","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment or mention","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookSocialSignal","description":"Signal info for social signals (social_mentions, social_reactions,\ncompetitor_social_reactions, company_engagement, company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorSocialLeadPayload","description":"Webhook payload for ``competitor_social_reactions``.\n\nSame shape as ``WebhookSocialLeadPayload`` but with a dedicated\nexample whose ``signal.tracked_contact`` correctly reflects this\nsignal's semantic — the LinkedIn URL of the employee at the tracked\ncompetitor whose reaction surfaced the post (NOT the post author).\nSchema-only subclass so the OpenAPI docs render an accurate\nexample on the create-signal endpoint's callback section.","examples":[{"company":{"linkedin_url":"https://linkedin.com/company/aicompany","name":"AI Company","website":"https://aicompany.com"},"contact":{"city":"Lyon","country_code":"FR","created_at":"2026-02-24T14:30:00+00:00","email":"sophie.bernard@aicompany.com","first_name":"Sophie","last_name":"Bernard","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://linkedin.com/in/sophiebernard","location":"Lyon, France","matched_persona":"Head of AI","phone":"+33611223344","sales_navigator_profile_url":"https://linkedin.com/sales/lead/ACoAAA...","title":"Head of AI"},"signal":{"engagement_type":"poster","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Social Reactions","last_signal_date":"2026-02-24","mention_content":"","name":"What lemlist's GTM team is reading","post_author_first_name":"Sophie","post_author_last_name":"Bernard","post_content":"Excited to share our latest AI breakthrough — a new model that handles multi-modal inputs at half the latency.","post_date":"2026-02-23","post_url":"https://linkedin.com/feed/update/urn:li:activity:567890","tracked_company":"https://www.linkedin.com/company/lemlist/","tracked_contact":"https://linkedin.com/in/alice-lemlist","type":"competitor_social_reactions"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the contact whose engagement surfaced this post to us. For ``competitor_social_reactions``, this is the employee at the tracked competitor (one of the URLs in ``linkedinCompanyUrls``) whose like/comment bubbled the post up — use it to trace the lead back to a specific named buyer at the competitor. For social_mentions / social_reactions, this is the post author.","default":""},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the company whose engagement surfaced this lead. For ``competitor_social_reactions``, this is the entry from ``linkedinCompanyUrls`` that the ``tracked_contact`` works at. For other social signals, the company the system was monitoring.","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment or mention","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookSocialSignal","description":"Signal info for social signals (social_mentions, social_reactions,\ncompetitor_social_reactions, company_engagement, company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookCompetitorSocialLeadPayload","description":"Webhook payload for ``competitor_social_reactions``.\n\nSame shape as ``WebhookSocialLeadPayload`` but with a dedicated\nexample whose ``signal.tracked_contact`` correctly reflects this\nsignal's semantic — the LinkedIn URL of the employee at the tracked\ncompetitor whose reaction surfaced the post (NOT the post author).\nSchema-only subclass so the OpenAPI docs render an accurate\nexample on the create-signal endpoint's callback section.","examples":[{"company":{"linkedin_url":"https://linkedin.com/company/aicompany","name":"AI Company","website":"https://aicompany.com"},"contact":{"city":"Lyon","country_code":"FR","created_at":"2026-02-24T14:30:00+00:00","email":"sophie.bernard@aicompany.com","first_name":"Sophie","last_name":"Bernard","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://linkedin.com/in/sophiebernard","location":"Lyon, France","matched_persona":"Head of AI","phone":"+33611223344","sales_navigator_profile_url":"https://linkedin.com/sales/lead/ACoAAA...","title":"Head of AI"},"signal":{"engagement_type":"poster","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Competitor Social Reactions","last_signal_date":"2026-02-24","mention_content":"","name":"What lemlist's GTM team is reading","post_author_first_name":"Sophie","post_author_last_name":"Bernard","post_content":"Excited to share our latest AI breakthrough — a new model that handles multi-modal inputs at half the latency.","post_date":"2026-02-23","post_url":"https://linkedin.com/feed/update/urn:li:activity:567890","tracked_company":"https://www.linkedin.com/company/lemlist/","tracked_contact":"https://linkedin.com/in/alice-lemlist","type":"competitor_social_reactions"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/department-growth":{"post":{"tags":["Signals"],"summary":"Create Department Growth signal","description":"Find decision-makers at companies where a specific department is rapidly growing or shrinking — immediately surface your ideal personas (Sales VPs, Engineering leads, etc.) as these organizational changes happen.\n\n**Input:** a name for the signal (name), a department to track (department), your ICP filters (companySizeFilters, locations, industryFilters), a growth percentage range (growthMin and growthMax—use negative numbers to find shrinking departments), and target persona titles (targetPersonas, with enablePersonaLookup set to true). Optional: your webhook endpoint (webhookUrl — omit it to read leads with GET /api/v1/signals/{signalId}/leads or a connected CRM), email/phone enrichment (getEmails, getPhones), a daily lead cap (dailyLeadLimit), and an initial status (status—defaults to `draft`; set to `active` to start collecting).\n\n**Output:** once active, the signal scans daily for companies that have newly entered your growth band. Each matching company is screened for your target personas; matching people are delivered to your webhookUrl, enriched with contact details if requested. Persona targeting is required: no leads are produced unless enablePersonaLookup is on with at least one persona specified in targetPersonas.\n\n**Use cases:**\n- Function-specific pitch — a growing sales team → GTM tools; a growing eng team → dev tools.\n- Budget signal — department growth means budget is being allocated to that function.","operationId":"create_department_growth_signal_api_v1_signals_department_growth_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/DepartmentGrowthConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":25},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"DepartmentGrowthCreate","description":"Create a Department Growth signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500"],"department":"Sales","enablePersonaLookup":true,"getEmails":true,"getPhones":false,"growthMax":100,"growthMin":20,"industryFilters":["Software Development"],"locations":["France"],"personaExportMode":"top_ranked","targetPersonas":["Sales Director","Growth Director","Business Developer"]},"dailyLeadLimit":25,"name":"Companies scaling their sales team","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies scaling their sales team","value":{"name":"Companies scaling their sales team","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"department":"Sales","locations":["France"],"companySizeFilters":["51-200","201-500"],"industryFilters":["Software Development"],"growthMin":20,"growthMax":100,"enablePersonaLookup":true,"targetPersonas":["Sales Director","Growth Director","Business Developer"],"personaExportMode":"top_ranked","getEmails":true,"getPhones":false}}}}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"b2c3d4e5-f6a7-8901-bcde-f01234567890","name":"Companies scaling their sales team","status":"active","signalTypeId":"department_growth","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"department":"Sales","locations":["France"],"companySizeFilters":["51-200","201-500"],"industryFilters":["Software Development"],"growthMin":20,"growthMax":100,"enablePersonaLookup":true,"targetPersonas":["Sales Director","Growth Director","Business Developer"],"getEmails":true,"getPhones":false},"dailyLeadLimit":25,"leadsToday":3,"leadsTotal":3,"duplicateHandling":"refuse","createdAt":"2026-07-03T09:00:00Z","updatedAt":"2026-07-03T09:00:00Z","lastLeadAt":"2026-07-03T09:15:00Z"}}}},"400":{"description":"Missing required config fields when creating as active","content":{"application/json":{"example":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["locations"],"missing_field_labels":["Locations"]}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_department_growth","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookDepartmentGrowthPayload","description":"Webhook payload for the department_growth signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"department_growth","last_signal_date":"2026-05-31","name":"Companies scaling their sales team","tracked_company":"","type":"department_growth"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookDepartmentGrowthPayload","description":"Webhook payload for the department_growth signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"department_growth","last_signal_date":"2026-05-31","name":"Companies scaling their sales team","tracked_company":"","type":"department_growth"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/dormant-linkedin-poster":{"post":{"tags":["Signals"],"summary":"Create Dormant LinkedIn Poster signal","description":"Get people who used to post regularly on LinkedIn and have gone quiet — a reachable audience for anyone selling content, ghostwriting or personal branding.\n\n**Input:** `targetPersonas` and the usual firmographic filters (`companySizeFilters`, `locations`, `industryFilters`). `getEmails` adds contact enrichment.\n\n**Output:** person-level leads — name, title, LinkedIn URL, company — with the dormancy window that qualified them.\n\n**Use cases:**\n- *Ghostwriting and content services* — someone who stopped posting has already shown intent, then hit a constraint.\n- *Personal branding* — founders who went quiet are the clearest fit.\n- *Re-activation offers* — the pitch writes itself from the observed pause.","operationId":"create_dormant_linkedin_poster_signal_api_v1_signals_dormant_linkedin_poster_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/DormantLinkedInPosterConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"DormantLinkedInPosterCreate","examples":[{"config":{"companySizeFilters":["1-10","11-50"],"getEmails":true,"locations":["France"],"targetPersonas":["CEO"]},"dailyLeadLimit":30,"name":"Founders who stopped posting (FR)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Founders who stopped posting (FR)","value":{"name":"Founders who stopped posting (FR)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":30,"status":"active","config":{"targetPersonas":["CEO"],"locations":["France"],"companySizeFilters":["1-10","11-50"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Founders who stopped posting (FR)","status":"active","signalTypeId":"dormant_linkedin_poster","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"targetPersonas":["CEO"],"locations":["France"],"companySizeFilters":["1-10","11-50"],"getEmails":true},"dailyLeadLimit":30,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected. Person-level: `contact` always carries the person.","operationId":"dormant_linkedin_poster_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookDormantPosterPayload","description":"Webhook payload for the dormant_linkedin_poster signal.\n\nPerson-level: ``contact`` always carries the person. Same shape as the other\nperson-based payloads, but declared separately so the generated client names\nthe type after THIS signal — sharing WebhookPersonLeadPayload made a client\ncall it after the competitor-relationship signal.\n\nThe example is a real payload captured from the production push path on\n2026-07-30.","examples":[{"company":{"description":"","employee_count":"","employee_range":"11-50","homepage_title":"","hq_city":"Paris","hq_country_code":"FR","industry":"Design Services","linkedin_url":"https://www.linkedin.com/company/ateliernord","location":"Paris, France","meta_description":"","name":"Atelier Nord","tech_stack":"","website":"https://ateliernord.fr"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-07-30T09:12:44+00:00","email":"","first_name":"Camille","last_name":"Rousseau","lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","linkedin_profile_url":"https://www.linkedin.com/in/camille-rousseau-demo","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"Founder & CEO"},"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","last_signal":"Dormant LinkedIn Poster","last_signal_date":"2026-07-30","name":"Founders who stopped posting (FR)","tracked_company":"","type":"dormant_linkedin_poster"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Founders who stopped posting (FR)","type":"dormant_linkedin_poster","last_signal":"Dormant LinkedIn Poster","last_signal_date":"2026-07-30","tracked_company":""},"contact":{"lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","created_at":"2026-07-30T09:12:44+00:00","first_name":"Camille","last_name":"Rousseau","email":"","phone":"","title":"Founder & CEO","location":"Paris, France","country_code":"FR","city":"Paris","linkedin_profile_url":"https://www.linkedin.com/in/camille-rousseau-demo","sales_navigator_profile_url":"","matched_persona":""},"company":{"name":"Atelier Nord","website":"https://ateliernord.fr","linkedin_url":"https://www.linkedin.com/company/ateliernord","description":"","industry":"Design Services","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"11-50","tech_stack":"","homepage_title":"","meta_description":""}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookDormantPosterPayload","description":"Webhook payload for the dormant_linkedin_poster signal.\n\nPerson-level: ``contact`` always carries the person. Same shape as the other\nperson-based payloads, but declared separately so the generated client names\nthe type after THIS signal — sharing WebhookPersonLeadPayload made a client\ncall it after the competitor-relationship signal.\n\nThe example is a real payload captured from the production push path on\n2026-07-30.","examples":[{"company":{"description":"","employee_count":"","employee_range":"11-50","homepage_title":"","hq_city":"Paris","hq_country_code":"FR","industry":"Design Services","linkedin_url":"https://www.linkedin.com/company/ateliernord","location":"Paris, France","meta_description":"","name":"Atelier Nord","tech_stack":"","website":"https://ateliernord.fr"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-07-30T09:12:44+00:00","email":"","first_name":"Camille","last_name":"Rousseau","lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","linkedin_profile_url":"https://www.linkedin.com/in/camille-rousseau-demo","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"Founder & CEO"},"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","last_signal":"Dormant LinkedIn Poster","last_signal_date":"2026-07-30","name":"Founders who stopped posting (FR)","tracked_company":"","type":"dormant_linkedin_poster"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/employee-departure":{"post":{"tags":["Signals"],"summary":"Create Employee Departure signal","description":"Reach people who just inherited a vacant role at your target accounts — when a VP Sales leaves, contact the CEO or Head of HR now managing that gap.\n\n**Input:** the roles to watch departing (`jobTitles`, `customTitles`); which people at the now-vacated company to contact (`deliverPersonas`); company filters (`companySizeFilters`, `locations`, `industryFilters`, `excludedLocations`, `excludedTitles`); enrichment flags (`getEmails`, `getPhones`).\n\n**Output:** each person matching a `deliverPersona` at a company where someone in a watched role just left is pushed to your `webhookUrl` as an enriched lead; non-matching departures are filtered out.\n\n**Use cases:**\n- Gap-filling pitch — when a role empties, offer to cover the gap (staffing, tooling, services) to whoever now owns it.\n- Backfill timing — recruiting vendors pitch the backfill the moment the seat opens.\n- Relationship-risk alert — warn your CS team when your champion leaves a customer account.","operationId":"create_employee_departure_signal_api_v1_signals_employee_departure_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/EmployeeDepartureConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"EmployeeDepartureCreate","description":"Create an Employee Departure signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500"],"customTitles":["Chief Revenue Officer"],"deliverPersonas":["CEO","Head of HR"],"detectTechnologies":false,"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedLocations":[],"excludedTitles":[],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"jobTitles":["VP Sales","Head of Sales"],"locations":["France"]},"dailyLeadLimit":50,"name":"Key departures at target accounts","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Key departures at target accounts","value":{"name":"Key departures at target accounts","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500"],"jobTitles":["VP Sales","Head of Sales"],"customTitles":["Chief Revenue Officer"],"locations":["France"],"excludedLocations":[],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":[],"deliverPersonas":["CEO","Head of HR"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Key departures at target accounts","status":"active","signalTypeId":"employee_departure","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500"],"jobTitles":["VP Sales","Head of Sales"],"customTitles":["Chief Revenue Officer"],"locations":["France"],"excludedLocations":[],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":[],"deliverPersonas":["CEO","Head of HR"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{"allowUnknownCompanySize":false},"warnings":[{"code":"UNKNOWN_SIZE_NOT_ACCEPTED","severity":"info","field":"allowUnknownCompanySize","message":"Companies whose size cannot be determined are accepted only when the size selection includes a band under 51 employees (\"Self-employed\", \"1-10\", \"11-50\"). This selection does not, so such companies are not delivered.","values":[]}]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_employee_departure","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn URL of the employee who left the tracked company","default":""},"departed_role":{"type":"string","title":"Departed Role","description":"Job title of the departed employee","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookEmployeeDepartureSignal","description":"Signal info for the employee_departure signal.\n\n``tracked_company`` is the FORMER company (the one the person just left);\nthe lead itself is a decision-maker at that company. ``tracked_contact`` is\nthe departed person, and ``departed_role`` their (anonymized) role title."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookEmployeeDeparturePayload","description":"Webhook payload for the employee_departure signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"CEO","phone":"","sales_navigator_profile_url":"","title":"Chief Executive Officer"},"signal":{"departed_role":"VP of Sales","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Employee Departure","last_signal_date":"2026-05-31","name":"Vacated VP Sales roles","tracked_company":"https://www.linkedin.com/company/techcorp/","tracked_contact":"https://www.linkedin.com/in/marie-dupont/","type":"employee_departure"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn URL of the employee who left the tracked company","default":""},"departed_role":{"type":"string","title":"Departed Role","description":"Job title of the departed employee","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookEmployeeDepartureSignal","description":"Signal info for the employee_departure signal.\n\n``tracked_company`` is the FORMER company (the one the person just left);\nthe lead itself is a decision-maker at that company. ``tracked_contact`` is\nthe departed person, and ``departed_role`` their (anonymized) role title."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookEmployeeDeparturePayload","description":"Webhook payload for the employee_departure signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"CEO","phone":"","sales_navigator_profile_url":"","title":"Chief Executive Officer"},"signal":{"departed_role":"VP of Sales","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Employee Departure","last_signal_date":"2026-05-31","name":"Vacated VP Sales roles","tracked_company":"https://www.linkedin.com/company/techcorp/","tracked_contact":"https://www.linkedin.com/in/marie-dupont/","type":"employee_departure"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/event-attendees":{"post":{"tags":["Signals"],"summary":"Create Event Attendees signal","description":"Turn a LinkedIn event's attendee list into leads. Point the signal at one or more LinkedIn event URLs and every person attending — filtered to your target personas and ICP — is delivered to your `webhookUrl` as an enriched lead. Event attendees are high-intent: they self-selected into a topic, so you reach an audience that already raised its hand.\n\n**Input:** signal `name`, `webhookUrl`, and a `config` object with the LinkedIn event URLs to track (`eventUrls`, required — each must contain the event's numeric id, e.g. `.../events/<slug>7318198749535633408/`), plus your ICP filters: `targetPersonas` and `customPersonaTitles` (which attendees qualify, matched on their headline), `excludedTitles`, `companySizeFilters` / `excludedCompanySizeFilters`, `locations` / `excludedLocations`, `industryFilters` / `excludedIndustryFilters`. Industry values must be the exact names returned by `GET /api/v1/signals/industries` — a single industry (`\"Software Development\"`) or a category (`\"Technology and Media\"`); matching is exact, so a near-miss matches nothing. An attendee whose company industry cannot be determined is **kept**, not dropped, when you filter by industry (their `company.industry` is then `\"\"`); an industry exclusion likewise only removes attendees whose industry is known. Optional `getEmails` adds email enrichment. Top-level `dailyLeadLimit` (1–999,999, default 100), `status` (`draft` | `active` | `paused`, default `draft`), and `duplicateHandling` (`refuse` | `allow` | `Xd`, default `allow`) complete the request.\n\n**Output:** `201 Created` returns the signal object (`id`, `name`, `status`, `signalTypeId`, `webhookUrl`, `config`, `dailyLeadLimit`, `leadsToday`, `leadsTotal`, `duplicateHandling`, `createdAt`, `updatedAt`, `lastLeadAt`). Each matching attendee is then POSTed to your `webhookUrl` as a JSON lead (`WebhookEventAttendeesPayload`) with three blocks. `signal`: `id`, `name`, `type` (`event_attendees`), `last_signal` (\"Event Attendees\"), `last_signal_date` (YYYY-MM-DD), and `tracked_company` — the LinkedIn event URL the attendee was found at. `contact`: `lead_id`, `created_at`, `first_name`, `last_name`, `email` (when `getEmails` is enabled), `phone`, `title`, `location`, `linkedin_profile_url`, `sales_navigator_profile_url`, `matched_persona`. `company`: `name`, `website`, `linkedin_url`, `description`, `industry`, `location`, `employee_count`, `employee_range`, `tech_stack`, `homepage_title`, `meta_description` — the company fields populate when you filter by company size or industry. Every documented key is always present; unavailable values are the empty string `\"\"` (never null). Attendees outside your persona or ICP filters are dropped and never sent.\n\n**Use cases:**\n- Warm-intent outreach — attendees self-selected into your topic; open with the exact event they showed up to.\n- Conference & webinar follow-up — reach everyone who attended a relevant industry event, not just the few you met.\n- Competitive events — capture the audience of a competitor's or partner's webinar and pitch your alternative.\n- Persona-filtered guest lists — keep only the decision-makers (e.g. CMOs, Heads of Growth) among the attendees.","operationId":"create_event_attendees_signal_api_v1_signals_event_attendees_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/EventAttendeesConfig","description":"Signal configuration — the LinkedIn event URLs to track plus your ICP filters"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused."}},"type":"object","required":["name","config"],"title":"EventAttendeesCreate","description":"Create an Event Attendees signal.","examples":[{"config":{"companySizeFilters":["201-500","501-1000","1001-5000"],"customPersonaTitles":["Head of Growth"],"eventUrls":["https://www.linkedin.com/events/the-future-of-marketing-webinar-7318198749535633408/"],"getEmails":true,"getPhones":false,"industryFilters":["Software Development"],"locations":["France"],"targetPersonas":["CMO","Marketing Director"]},"dailyLeadLimit":50,"name":"Marketing leaders at industry webinars","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Marketing leaders at industry webinars","value":{"name":"Marketing leaders at industry webinars","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"eventUrls":["https://www.linkedin.com/events/the-future-of-marketing-webinar-7318198749535633408/"],"getEmails":true,"getPhones":false,"targetPersonas":["CMO","Marketing Director"],"customPersonaTitles":["Head of Growth"],"companySizeFilters":["201-500","501-1000","1001-5000"],"locations":["France"],"industryFilters":["Software Development"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"c1d2e3f4-a5b6-7890-cdef-1234567890ab","name":"Marketing leaders at industry webinars","status":"active","signalTypeId":"event_attendees","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"eventUrls":["https://www.linkedin.com/events/the-future-of-marketing-webinar-7318198749535633408/"],"getEmails":true,"getPhones":false,"targetPersonas":["CMO","Marketing Director"],"customPersonaTitles":["Head of Growth"],"companySizeFilters":["201-500","501-1000","1001-5000"],"locations":["France"],"industryFilters":["Software Development"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00"}}}},"400":{"description":"Invalid request: missing required config (event URLs), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (event URLs)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["event_urls"],"missing_field_labels":["Event URLs"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"POSTed to your `webhookUrl` when an event attendee becomes a lead. `signal.tracked_company` is the LinkedIn event URL the attendee was found at. Absent values are the empty string `\"\"`, never null.","operationId":"person_lead_webhook_event_attendees","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookEventAttendeesPayload","description":"Webhook payload for the **event_attendees** signal.\n\nSame structure as any person lead, but with an event-specific example:\n``signal.type`` is ``event_attendees``, ``signal.last_signal`` is\n``\"Event Attendees\"``, and ``signal.tracked_company`` is the **LinkedIn event\nURL** the attendee was found at (not a company URL). The company block is\npopulated when you filter by company size or industry; enrichment fields\n(email, tech_stack, homepage) populate when those toggles are enabled.\nExample shape verified against a live capture on 2026-07-14.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp — Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Marketing Director","phone":"","sales_navigator_profile_url":"","title":"Group Marketing Director"},"signal":{"id":"c1d2e3f4-a5b6-7890-cdef-1234567890ab","last_signal":"Event Attendees","last_signal_date":"2026-05-31","name":"Marketing leaders at industry webinars","tracked_company":"https://www.linkedin.com/events/the-future-of-marketing-webinar-7318198749535633408/","type":"event_attendees"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookPersonSignal"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookEventAttendeesPayload","description":"Webhook payload for the **event_attendees** signal.\n\nSame structure as any person lead, but with an event-specific example:\n``signal.type`` is ``event_attendees``, ``signal.last_signal`` is\n``\"Event Attendees\"``, and ``signal.tracked_company`` is the **LinkedIn event\nURL** the attendee was found at (not a company URL). The company block is\npopulated when you filter by company size or industry; enrichment fields\n(email, tech_stack, homepage) populate when those toggles are enabled.\nExample shape verified against a live capture on 2026-07-14.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp — Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Marketing Director","phone":"","sales_navigator_profile_url":"","title":"Group Marketing Director"},"signal":{"id":"c1d2e3f4-a5b6-7890-cdef-1234567890ab","last_signal":"Event Attendees","last_signal_date":"2026-05-31","name":"Marketing leaders at industry webinars","tracked_company":"https://www.linkedin.com/events/the-future-of-marketing-webinar-7318198749535633408/","type":"event_attendees"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-acquisition":{"post":{"tags":["Signals"],"summary":"Create Forecasted Acquisition signal","description":"Likely acquisition targets — delivered engage ahead of the deal, before procurement freezes and the stack gets consolidated.\n\n**Input:** all optional — `companySizeFilters`, `locations`, `industryFilters` (LinkedIn taxonomy, mapped to our forecast industry categories for you) and their `excluded*` counterparts. Enable `enablePersonaTargeting` with `targetPersonas` to add contacts, and `getEmails` / `getPhones` for enrichment. There is no forecast-strength parameter: only the strongest tier is ever served.\n\n**Output:** company-level leads — name, domain, LinkedIn URL, industry, size, location. Contacts are delivered only when persona targeting is on.\n\n**Use cases:**\n- *Beat the freeze* — procurement usually locks down once a deal is signed.\n- *Integration services* — an acquisition triggers migration and consolidation work.\n- *Relationship timing* — the acquirer inherits the vendors already in place.","operationId":"create_forecasted_acquisition_signal_api_v1_signals_forecasted_acquisition_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedAcquisitionCreate","examples":[{"config":{"companySizeFilters":["11-50","51-200"],"getEmails":true,"industryFilters":["Software Development"],"locations":["France"]},"dailyLeadLimit":25,"name":"Likely acquisition targets (EU software, 51-500)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Likely acquisition targets (EU software, 51-500)","value":{"name":"Likely acquisition targets (EU software, 51-500)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Likely acquisition targets (EU software, 51-500)","status":"active","signalTypeId":"forecasted_acquisition","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a forecast match is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. Only the strongest forecast tier is ever delivered, so a lead arriving IS the signal — there is no likelihood field to read.","operationId":"forecasted_acquisition_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Likely acquisition targets (US software)","type":"forecasted_acquisition","last_signal":"Forecasted Acquisition","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Unframe","website":"https://unframe.com","linkedin_url":"https://www.linkedin.com/company/unframe","industry":"SaaS","location":"United States","hq_country_code":"US","hq_city":"","employee_count":"","employee_range":"51-200"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-acquisition-watchlist":{"post":{"tags":["Signals"],"summary":"Create Forecasted Acquisition Watchlist signal","description":"Know which of your accounts is likely to be acquired, while the incumbent team still owns its decisions.\n\nUpload the accounts you care about; when one of them becomes a likely acquisition target, it becomes a lead. This is forward-looking - it fires BEFORE the event, not after it. There is deliberately no company-size, location or industry filter: you named the companies, which answers that far more precisely than an ICP could, and re-filtering your own list could only drop accounts you asked us to watch.\n\n**Input:** `companies` (names, domains or LinkedIn company URLs), optional `excludedCompanyUrls`, and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`). There is no strength setting: only the strongest tier is ever delivered, so a lead arriving IS the signal.\n\n**Output:** one lead per watched company as it enters that tier, delivered to your `webhookUrl`. A company is delivered once per deduplication window.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Reach the incumbent team first - a likely acquisition target still owns its own decisions, and will not once the deal closes.\n- Protect a renewal - if a customer is a likely target, plan the relationship with whoever will own it next.","operationId":"create_forecasted_acquisition_watchlist_signal_api_v1_signals_forecasted_acquisition_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedAcquisitionWatchlistCreate","examples":[{"config":{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"targetPersonas":["Head of Sales"]},"dailyLeadLimit":25,"name":"My accounts, a likely acquisition target","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"My accounts, a likely acquisition target","value":{"name":"My accounts, a likely acquisition target","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"lemlist"],"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts, a likely acquisition target","status":"active","signalTypeId":"forecasted_acquisition_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per watched company as it enters the tier.","operationId":"forecasted_acquisition_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts","type":"forecasted_acquisition_watchlist","last_signal":"Watched Company Likely Acquisition Target","last_signal_date":"2026-08-13","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Payfit","website":"https://payfit.com","linkedin_url":"https://www.linkedin.com/company/payfit","industry":"Software","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"501-1000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-funding":{"post":{"tags":["Signals"],"summary":"Create Forecasted Funding signal","description":"Companies likely to raise — delivered before the round is announced — while budgets are being planned and vendors are still up for debate.\n\n**Input:** all optional — `companySizeFilters`, `locations`, `industryFilters` (LinkedIn taxonomy, mapped to our forecast industry categories for you) and their `excluded*` counterparts. Enable `enablePersonaTargeting` with `targetPersonas` to add contacts, and `getEmails` / `getPhones` for enrichment. There is no forecast-strength parameter: only the strongest tier is ever served.\n\n**Output:** company-level leads — name, domain, LinkedIn URL, industry, size, location. Contacts are delivered only when persona targeting is on.\n\n**Use cases:**\n- *Get in before the raise* — land while the budget is being drafted, not after every vendor has pitched.\n- *Tooling expansion* — new funding almost always means new headcount and new tools.\n- *Warm the relationship* — reach out pre-announcement and you are a familiar name when spend unlocks.","operationId":"create_forecasted_funding_signal_api_v1_signals_forecasted_funding_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedFundingCreate","examples":[{"config":{"companySizeFilters":["11-50","51-200"],"getEmails":true,"industryFilters":["Software Development"],"locations":["France"]},"dailyLeadLimit":25,"name":"Companies likely to raise (FR/US software, 11-200)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies likely to raise (FR/US software, 11-200)","value":{"name":"Companies likely to raise (FR/US software, 11-200)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies likely to raise (FR/US software, 11-200)","status":"active","signalTypeId":"forecasted_funding","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a forecast match is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. Only the strongest forecast tier is ever delivered, so a lead arriving IS the signal — there is no likelihood field to read.","operationId":"forecasted_funding_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies likely to raise (US software)","type":"forecasted_funding","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Kintsugi AI","website":"https://kintsugi.ai","linkedin_url":"https://www.linkedin.com/company/kintsugi","industry":"Artificial Intelligence (AI)","location":"United States","hq_country_code":"US","hq_city":"","employee_count":"","employee_range":"51-200"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-funding-watchlist":{"post":{"tags":["Signals"],"summary":"Create Forecasted Funding Watchlist signal","description":"Know which of your accounts is about to have money, before the round is announced.\n\nUpload the accounts you care about; when one of them becomes likely to raise, it becomes a lead. This is forward-looking - it fires BEFORE the event, not after it. There is deliberately no company-size, location or industry filter: you named the companies, which answers that far more precisely than an ICP could, and re-filtering your own list could only drop accounts you asked us to watch.\n\n**Input:** `companies` (names, domains or LinkedIn company URLs), optional `excludedCompanyUrls`, and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`). There is no strength setting: only the strongest tier is ever delivered, so a lead arriving IS the signal.\n\n**Output:** one lead per watched company as it enters that tier, delivered to your `webhookUrl`. A company is delivered once per deduplication window.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Get in before the round - reach a watched account while it is likely to raise, when the budget conversation is still forming rather than already spent.\n- Prioritise a long list - rank the accounts you already track by which are about to have money, instead of working them alphabetically.","operationId":"create_forecasted_funding_watchlist_signal_api_v1_signals_forecasted_funding_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedFundingWatchlistCreate","examples":[{"config":{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"targetPersonas":["Head of Sales"]},"dailyLeadLimit":25,"name":"My accounts, likely to raise","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"My accounts, likely to raise","value":{"name":"My accounts, likely to raise","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"lemlist"],"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts, likely to raise","status":"active","signalTypeId":"forecasted_funding_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per watched company as it enters the tier.","operationId":"forecasted_funding_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts","type":"forecasted_funding_watchlist","last_signal":"Watched Company Likely to Raise","last_signal_date":"2026-08-13","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Payfit","website":"https://payfit.com","linkedin_url":"https://www.linkedin.com/company/payfit","industry":"Software","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"501-1000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-growth":{"post":{"tags":["Signals"],"summary":"Create Forecasted Growth signal","description":"Companies about to scale — delivered every company here is double-qualified: expected to scale AND on track to raise, list or be acquired.\n\n**Input:** all optional — `companySizeFilters`, `locations`, `industryFilters` (LinkedIn taxonomy, mapped to our forecast industry categories for you) and their `excluded*` counterparts. Enable `enablePersonaTargeting` with `targetPersonas` to add contacts, and `getEmails` / `getPhones` for enrichment. There is no forecast-strength parameter: only the strongest tier is ever served.\n\n**Output:** company-level leads — name, domain, LinkedIn URL, industry, size, location. Contacts are delivered only when persona targeting is on.\n\n**Use cases:**\n- *Headcount-driven demand* — scaling teams need tooling, onboarding and infrastructure.\n- *Land before the crowd* — growth attracts every vendor; arrive first.\n- *Highest-intent slice* — the double qualification makes this the narrowest, strongest list of the four.","operationId":"create_forecasted_growth_signal_api_v1_signals_forecasted_growth_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedGrowthCreate","examples":[{"config":{"companySizeFilters":["11-50","51-200"],"getEmails":true,"industryFilters":["Software Development"],"locations":["France"]},"dailyLeadLimit":25,"name":"Companies about to scale (FR, 11-200)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies about to scale (FR, 11-200)","value":{"name":"Companies about to scale (FR, 11-200)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies about to scale (FR, 11-200)","status":"active","signalTypeId":"forecasted_growth","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a forecast match is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. Only the strongest forecast tier is ever delivered, so a lead arriving IS the signal — there is no likelihood field to read.","operationId":"forecasted_growth_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies about to scale (US)","type":"forecasted_growth","last_signal":"Forecasted Growth","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"General Compute","website":"https://generalcompute.io","linkedin_url":"https://www.linkedin.com/company/generalcompute","industry":"Cloud Computing","location":"United States","hq_country_code":"US","hq_city":"","employee_count":"","employee_range":"11-50"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-growth-watchlist":{"post":{"tags":["Signals"],"summary":"Create Forecasted Growth Watchlist signal","description":"Know which of your accounts is about to grow, and to make the headcount and tooling decisions that follow.\n\nUpload the accounts you care about; when one of them becomes expected to scale, it becomes a lead. This is forward-looking - it fires BEFORE the event, not after it. There is deliberately no company-size, location or industry filter: you named the companies, which answers that far more precisely than an ICP could, and re-filtering your own list could only drop accounts you asked us to watch.\n\n**Input:** `companies` (names, domains or LinkedIn company URLs), optional `excludedCompanyUrls`, and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`). There is no strength setting: only the strongest tier is ever delivered, so a lead arriving IS the signal.\n\n**Output:** one lead per watched company as it enters that tier, delivered to your `webhookUrl`. A company is delivered once per deduplication window.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Follow the scaling accounts - headcount, spend and tooling decisions follow growth; this surfaces which of your watched companies are about to make them.\n- Expansion timing - existing customers expected to scale are the ones whose seat count and needs are about to change.","operationId":"create_forecasted_growth_watchlist_signal_api_v1_signals_forecasted_growth_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedGrowthWatchlistCreate","examples":[{"config":{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"targetPersonas":["Head of Sales"]},"dailyLeadLimit":25,"name":"My accounts, expected to scale","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"My accounts, expected to scale","value":{"name":"My accounts, expected to scale","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"lemlist"],"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts, expected to scale","status":"active","signalTypeId":"forecasted_growth_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per watched company as it enters the tier.","operationId":"forecasted_growth_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts","type":"forecasted_growth_watchlist","last_signal":"Watched Company Expected to Scale","last_signal_date":"2026-08-13","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Payfit","website":"https://payfit.com","linkedin_url":"https://www.linkedin.com/company/payfit","industry":"Software","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"501-1000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-ipo":{"post":{"tags":["Signals"],"summary":"Create Forecasted IPO signal","description":"Companies on a path to going public — delivered the window when they staff up on compliance, finance and infrastructure, and buy the tooling that comes with it.\n\n**Input:** all optional — `companySizeFilters`, `locations`, `industryFilters` (LinkedIn taxonomy, mapped to our forecast industry categories for you) and their `excluded*` counterparts. Enable `enablePersonaTargeting` with `targetPersonas` to add contacts, and `getEmails` / `getPhones` for enrichment. There is no forecast-strength parameter: only the strongest tier is ever served.\n\n**Output:** company-level leads — name, domain, LinkedIn URL, industry, size, location. Contacts are delivered only when persona targeting is on.\n\n**Use cases:**\n- *Compliance and audit* — IPO readiness forces spend on controls, reporting and security.\n- *Finance tooling* — reporting standards tighten well before the listing.\n- *Scale-up hiring* — headcount plans accelerate ahead of the event.","operationId":"create_forecasted_ipo_signal_api_v1_signals_forecasted_ipo_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedIpoCreate","examples":[{"config":{"companySizeFilters":["11-50","51-200"],"getEmails":true,"industryFilters":["Software Development"],"locations":["France"]},"dailyLeadLimit":25,"name":"Companies on an IPO path (US, 501+)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies on an IPO path (US, 501+)","value":{"name":"Companies on an IPO path (US, 501+)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies on an IPO path (US, 501+)","status":"active","signalTypeId":"forecasted_ipo","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"companySizeFilters":["11-50","51-200"],"locations":["France"],"industryFilters":["Software Development"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a forecast match is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. Only the strongest forecast tier is ever delivered, so a lead arriving IS the signal — there is no likelihood field to read.","operationId":"forecasted_ipo_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies on an IPO path (US)","type":"forecasted_ipo","last_signal":"Forecasted IPO","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Helio Systems","website":"https://heliosystems.com","linkedin_url":"https://www.linkedin.com/company/heliosystems","industry":"Enterprise Software","location":"United States","hq_country_code":"US","hq_city":"","employee_count":"","employee_range":"1001-5000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/forecasted-ipo-watchlist":{"post":{"tags":["Signals"],"summary":"Create Forecasted IPO Watchlist signal","description":"Know which of your accounts is heading for an IPO, when it starts buying for scale and scrutiny.\n\nUpload the accounts you care about; when one of them becomes on a path to going public, it becomes a lead. This is forward-looking - it fires BEFORE the event, not after it. There is deliberately no company-size, location or industry filter: you named the companies, which answers that far more precisely than an ICP could, and re-filtering your own list could only drop accounts you asked us to watch.\n\n**Input:** `companies` (names, domains or LinkedIn company URLs), optional `excludedCompanyUrls`, and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`). There is no strength setting: only the strongest tier is ever delivered, so a lead arriving IS the signal.\n\n**Output:** one lead per watched company as it enters that tier, delivered to your `webhookUrl`. A company is delivered once per deduplication window.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Sell into IPO readiness - companies on a path to going public buy for scale, audit and compliance; this tells you which of your accounts just joined that group.\n- Time the exec conversation - the run-up is when new leadership and new budget lines appear at an account you already know.","operationId":"create_forecasted_ipo_watchlist_signal_api_v1_signals_forecasted_ipo_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/ForecastWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"ForecastedIpoWatchlistCreate","examples":[{"config":{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"targetPersonas":["Head of Sales"]},"dailyLeadLimit":25,"name":"My accounts, on a path to going public","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"My accounts, on a path to going public","value":{"name":"My accounts, on a path to going public","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"lemlist"],"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts, on a path to going public","status":"active","signalTypeId":"forecasted_ipo_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per watched company as it enters the tier.","operationId":"forecasted_ipo_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts","type":"forecasted_ipo_watchlist","last_signal":"Watched Company on a Path to IPO","last_signal_date":"2026-08-13","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Payfit","website":"https://payfit.com","linkedin_url":"https://www.linkedin.com/company/payfit","industry":"Software","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"501-1000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookForecastPayload","description":"Webhook payload for the forecast signals (forecasted_funding,\nforecasted_ipo, forecasted_acquisition, forecasted_growth).\n\nSame company-only envelope as the technographic signals: ``contact`` is\n``\"\"`` unless persona targeting is enabled, and the ``job_offer_*`` keys are\nalways empty.\n\nOnly the strongest forecast tier is ever delivered, so there is no\nlikelihood field to read — a lead arriving IS the signal.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"US","industry":"Artificial Intelligence (AI)","linkedin_url":"https://www.linkedin.com/company/kintsugi","location":"United States","name":"Kintsugi AI","website":"https://kintsugi.ai"},"contact":"","signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Forecasted Funding","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies likely to raise (US software)","type":"forecasted_funding"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/fundraising":{"post":{"tags":["Signals"],"summary":"Create Fundraising signal","description":"Identify companies that recently raised capital and reach decision-makers at funded companies while they're actively deploying that capital.\n\n**Input:** your notification webhook (`webhookUrl`), along with filtering rules in `config`: funding round types (`investmentTypes` — e.g. `seed`, `series_a`, `series_b`), funding amount range (`amountMin`, `amountMax` in USD), how recent (`announcedPeriod`: `24h`, `7d`, `30d`, `60d`, `90d`, `12m`), company geography and size (`hqLocations`/`excludedHqLocations`, `companySizeFilters`), industries to include/exclude (`industryFilters`/`excludedIndustryFilters`), investor names to include/exclude (`investorInclude`/`investorExclude`), and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`). You can also enrich results with email, phone, or technology detection (`getEmails`, `getPhones`, `detectTechnologies`).\n\n**Output:** each funding round matching your filters is pushed to `webhookUrl` as it is detected, with full deal data (funding stage, amount in both original and USD currency, investor names, announcement date, an AI-generated deal summary, a use-of-funds excerpt, and the source article URL). When persona targeting is enabled, a decision-maker at the funded company is resolved and delivered in `contact`; otherwise `contact` is an empty string (`\"\"`) — always present, never null.\n\n**Use cases:**\n- Fresh-budget outreach — newly-funded companies have capital to deploy; time your pitch to the raise.\n- Scale-enablement — pitch the tools that support the growth the round is meant to fund.","operationId":"create_fundraising_signal_api_v1_signals_fundraising_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FundraisingCreate"},"examples":{"example1":{"summary":"Series A+ in France","value":{"name":"Series A+ in France","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"investmentTypes":["seed","series_a","series_b"],"amountMin":1000000,"amountMax":50000000,"announcedPeriod":"30d","hqLocations":["France","Germany"],"industryFilters":["Software Development","Financial Services"],"companySizeFilters":["11-50","51-200"],"investorInclude":["Sequoia","a16z"],"investorExclude":[],"enablePersonaTargeting":true,"targetPersonas":["CEO","Finance Director"],"customPersonaTitles":["Chief Growth Officer"],"personaExportMode":"top_ranked","personaLocations":["France"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Series A+ in France","status":"active","signalTypeId":"fundraising","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"investmentTypes":["seed","series_a","series_b"],"amountMin":1000000,"amountMax":50000000,"announcedPeriod":"30d","hqLocations":["France","Germany"],"industryFilters":["Software Development","Financial Services"],"companySizeFilters":["11-50","51-200"],"investorInclude":["Sequoia","a16z"],"investorExclude":[],"enablePersonaTargeting":true,"targetPersonas":["CEO","Finance Director"],"customPersonaTitles":["Chief Growth Officer"],"personaExportMode":"top_ranked","personaLocations":["France"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a funding round is detected. `contact` is null unless persona targeting is enabled.","operationId":"fundraising_webhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookFundraisingPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookFundraisingPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/fundraising-watchlist":{"post":{"tags":["Signals"],"summary":"Create Fundraising Watchlist signal","description":"Get told the day a company on YOUR list raises. Upload the accounts you care about and every funding round they announce becomes a lead, with the round type, amount and investors attached.\n\nWhere the Fundraising signal DISCOVERS companies from filters, this one starts from your list: your target accounts, your customers, or your competitors. There is deliberately no company-size, location or industry filter: you named the companies, which answers that far more precisely than an ICP could, and re-filtering your own list could only drop accounts you asked us to watch.\n\n**Input:** `companies` (names, domains or LinkedIn company URLs), and the same round filters as the open signal - `investmentTypes`, `amountMin` / `amountMax` (USD), `announcedPeriod` (default `30d`), `investorInclude` / `investorExclude` - plus optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`).\n\n**Output:** each qualifying round is delivered to your `webhookUrl`. With persona targeting off you get one company-level lead per round (`contact` empty); with it on you get decision-makers as person-leads. A round is delivered ONCE.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Time the raise, not the market - you already know which accounts you want; this tells you the week they close a round and the budget conversation is open.\n- Re-open a lost deal - a prospect who said no on price is a different buyer the day they raise a Series B, and you hear it before the press cycle does.\n- Prioritise the pipeline - feed the round type and amount into your scoring so reps work the accounts whose spending power just changed.","operationId":"create_fundraising_watchlist_signal_api_v1_signals_fundraising_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/FundraisingWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"FundraisingWatchlistCreate","examples":[{"config":{"amountMin":1000000,"announcedPeriod":"30d","companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"investmentTypes":["series_a","series_b","series_c"],"targetPersonas":["Head of Sales"]},"dailyLeadLimit":30,"name":"Funding at my target accounts","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Funding at my target accounts","value":{"name":"Funding at my target accounts","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":30,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"lemlist"],"investmentTypes":["series_a","series_b","series_c"],"amountMin":1000000,"announcedPeriod":"30d","enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Funding at my target accounts","status":"active","signalTypeId":"fundraising_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"investmentTypes":["series_a","series_b","series_c"],"amountMin":1000000,"announcedPeriod":"30d","enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true},"dailyLeadLimit":30,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent for each qualifying funding round at a watched company.","operationId":"fundraising_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"funding_type":{"type":"string","title":"Funding Type","description":"Round type (e.g. \"venture\", \"seed\")","default":""},"funding_stage":{"type":"string","title":"Funding Stage","description":"Stage (e.g. \"Series A\")","default":""},"funding_amount":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount","description":"Amount in original currency; \"\" when absent","default":""},"funding_amount_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount Usd","description":"Amount in USD; \"\" when absent","default":""},"funding_currency":{"type":"string","title":"Funding Currency","description":"ISO currency code","default":""},"investors":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Investors","description":"List of investor names; \"\" when absent"},"num_investors":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Num Investors","description":"Number of investors participating in the round; \"\" when absent","default":""},"funding_total_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Total Usd","description":"Total the company has raised to date in USD, across all rounds — not just this one; \"\" when absent","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD)","default":""},"company_crunchbase_url":{"type":"string","title":"Company Crunchbase Url","description":"Public funding profile URL","default":""},"article_summary":{"type":"string","title":"Article Summary","description":"AI-generated summary of the funding announcement article","default":""},"article_use_of_funds":{"type":"string","title":"Article Use Of Funds","description":"AI-extracted planned use of funds from the article","default":""},"article_source_url":{"type":"string","title":"Article Source Url","description":"URL of the source article about the funding round","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookFundraisingWatchlistSignal","description":"Signal info for a funding round at a WATCHED company.\n\nIdentical to the open fundraising signal's block. Declared separately so a\ngenerated client names this signal's type after this signal."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookFundraisingWatchlistPayload","description":"Webhook payload for fundraising_watchlist.\n\nSame shape as the open fundraising signal: the difference is which companies\nit can ever describe, not what it says about them. All documented keys are\nalways present; absent values are delivered as empty strings (``\"\"``), never\n``null``.","examples":[{"company":{"employee_range":"501-1000","hq_city":"Paris","hq_country_code":"FR","industry":"Software","linkedin_url":"https://www.linkedin.com/company/payfit","location":"Paris, France","name":"Payfit","website":"https://payfit.com"},"contact":"","signal":{"announcement_date":"2026-08-11","funding_amount":254000000,"funding_amount_usd":254000000,"funding_currency":"USD","funding_stage":"Late Stage Venture","funding_type":"series_c","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","investors":["General Atlantic","Eurazeo"],"last_signal":"Watched Company Raised","last_signal_date":"2026-08-13","name":"Funding at my target accounts","type":"fundraising_watchlist"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts","type":"fundraising_watchlist","last_signal":"Watched Company Raised","last_signal_date":"2026-08-13","funding_type":"series_c","funding_stage":"Late Stage Venture","funding_amount":254000000,"funding_amount_usd":254000000,"funding_currency":"USD","investors":["General Atlantic","Eurazeo"],"announcement_date":"2026-08-11","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Payfit","website":"https://payfit.com","linkedin_url":"https://www.linkedin.com/company/payfit","industry":"Software","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"501-1000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"funding_type":{"type":"string","title":"Funding Type","description":"Round type (e.g. \"venture\", \"seed\")","default":""},"funding_stage":{"type":"string","title":"Funding Stage","description":"Stage (e.g. \"Series A\")","default":""},"funding_amount":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount","description":"Amount in original currency; \"\" when absent","default":""},"funding_amount_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount Usd","description":"Amount in USD; \"\" when absent","default":""},"funding_currency":{"type":"string","title":"Funding Currency","description":"ISO currency code","default":""},"investors":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Investors","description":"List of investor names; \"\" when absent"},"num_investors":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Num Investors","description":"Number of investors participating in the round; \"\" when absent","default":""},"funding_total_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Total Usd","description":"Total the company has raised to date in USD, across all rounds — not just this one; \"\" when absent","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD)","default":""},"company_crunchbase_url":{"type":"string","title":"Company Crunchbase Url","description":"Public funding profile URL","default":""},"article_summary":{"type":"string","title":"Article Summary","description":"AI-generated summary of the funding announcement article","default":""},"article_use_of_funds":{"type":"string","title":"Article Use Of Funds","description":"AI-extracted planned use of funds from the article","default":""},"article_source_url":{"type":"string","title":"Article Source Url","description":"URL of the source article about the funding round","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookFundraisingWatchlistSignal","description":"Signal info for a funding round at a WATCHED company.\n\nIdentical to the open fundraising signal's block. Declared separately so a\ngenerated client names this signal's type after this signal."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookFundraisingWatchlistPayload","description":"Webhook payload for fundraising_watchlist.\n\nSame shape as the open fundraising signal: the difference is which companies\nit can ever describe, not what it says about them. All documented keys are\nalways present; absent values are delivered as empty strings (``\"\"``), never\n``null``.","examples":[{"company":{"employee_range":"501-1000","hq_city":"Paris","hq_country_code":"FR","industry":"Software","linkedin_url":"https://www.linkedin.com/company/payfit","location":"Paris, France","name":"Payfit","website":"https://payfit.com"},"contact":"","signal":{"announcement_date":"2026-08-11","funding_amount":254000000,"funding_amount_usd":254000000,"funding_currency":"USD","funding_stage":"Late Stage Venture","funding_type":"series_c","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","investors":["General Atlantic","Eurazeo"],"last_signal":"Watched Company Raised","last_signal_date":"2026-08-13","name":"Funding at my target accounts","type":"fundraising_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/gmb-listing":{"post":{"tags":["Signals"],"summary":"Create GMB Discovery signal","description":"Catch local businesses the moment they appear on Google Maps — newly indexed restaurants, plumbers, salons, and other categories across France or Belgium. Every new business matching your filters is pushed to your webhook.\n\n**Input:** country (FR or BE), category / subcategory (e.g., \"Restaurant\" or \"Italian restaurant\"), cities by name (e.g., \"Paris\", \"Lyon\"), postal codes (France), rating and review-count ranges, presence filters (hasPhone, hasEmail, hasWebsite, hasSiret), and APE/NAF codes (France-only). Optionally enable keepOnlyConfirmedNew (France-only) to cross-check the French SIRENE registry and drop false positives that were registered before a freshness cutoff (default 180 days, configurable); this switches per-lead pricing from 1 to 5 credits.\n\n**Output:** each newly-indexed business matching your filters is sent as a lead to your webhookUrl containing: company name, website URL, Google Maps URL, category, Google rating, review count, location, SIREN/VAT identifiers, and a generic business email if one is found on the business's website. This is a company-only signal (no person contacts). Optionally enrich each lead with email enrichment, phone enrichment, full SIRENE company data, detected technologies, or homepage content via getEmails/getPhones/getSireneData/detectTechnologies/getHomepageContent flags.\n\n**Use cases:**\n- Local-SMB outreach — reach new local businesses (agencies, SMB SaaS, suppliers) as they open.\n- Territory-based field sales — filter by city and category to feed a local rep's pipeline.","operationId":"create_gmb_listing_signal_api_v1_signals_gmb_listing_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/GmbListingConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"GmbListingCreate","description":"Create a GMB Discovery signal.","examples":[{"config":{"category":"Restaurant","cities":["Paris"],"country":"FR","hasPhone":true,"keepOnlyConfirmedNew":false},"dailyLeadLimit":100,"name":"New restaurants in Paris","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"},{"config":{"country":"FR","keepOnlyConfirmedNew":true,"subcategory":"Plumber"},"dailyLeadLimit":50,"name":"New plumbers across France, confirmed-new only","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"New restaurants in Paris","value":{"name":"New restaurants in Paris","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":100,"status":"active","config":{"country":"FR","category":"Restaurant","cities":["Paris"],"hasPhone":true,"keepOnlyConfirmedNew":false}}},"example2":{"summary":"New plumbers across France, confirmed-new only","value":{"name":"New plumbers across France, confirmed-new only","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"country":"FR","subcategory":"Plumber","keepOnlyConfirmedNew":true}}}}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"New restaurants in Paris","status":"active","signalTypeId":"gmb_listing","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"country":"FR","category":"Restaurant","cities":["Paris"],"hasPhone":true,"keepOnlyConfirmedNew":false,"getEmails":false},"dailyLeadLimit":100,"leadsToday":4,"leadsTotal":52,"duplicateHandling":"refuse","createdAt":"2026-01-15T10:30:00Z","updatedAt":"2026-03-16T08:00:00Z","lastLeadAt":"2026-03-15T14:22:00Z"}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a newly-listed Google Maps business matches your filters. `contact` is always null (company-only signal).","operationId":"gmb_lead_webhook_gmb_listing","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"place_id":{"type":"string","title":"Place Id","description":"Google Maps place ID of the business","default":""},"google_maps_url":{"type":"string","title":"Google Maps Url","description":"Google Maps URL for the business listing","default":""},"category":{"type":"string","title":"Category","description":"Google Maps category of the business","default":""},"rating":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Rating","description":"Google rating (0-5); \"\" when absent","default":""},"review_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Review Count","description":"Number of Google reviews; \"\" when absent","default":""},"siren":{"type":"string","title":"Siren","description":"French SIREN identifier (when resolved)","default":""},"vat":{"type":"string","title":"Vat","description":"VAT / national company registration number (when found on the business website)","default":""},"confirmed_new":{"anyOf":[{"type":"boolean"},{"type":"string"}],"title":"Confirmed New","description":"True when keepOnlyConfirmedNew is enabled and the business was confirmed as recently registered against the SIRENE registry. \"\" when not applicable.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookGmbListingSignal","description":"Signal info for GMB Discovery (gmb_listing) — a newly-listed Google Maps business."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless a generic business email was found on the website; then a role-based contact carrying that email (no first/last name). Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookGmbLeadPayload","description":"Webhook payload for GMB Discovery (gmb_listing).\n\nCompany-only signal. All documented keys are always present, and absent\nvalues are delivered as empty strings (``\"\"``), never ``null``. ``contact``\nis the empty string ``\"\"`` unless a generic business email was found on the\nlisting's website, in which case it carries that role-based address (no\nperson name).","examples":[{"company":{"employee_count":"","employee_range":"","hq_city":"Paris","hq_country_code":"FR","industry":"Italian restaurant","linkedin_url":"","location":"Paris, France","name":"Trattoria Bella","website":"https://trattoria-bella.fr"},"contact":{"city":"","country_code":"","created_at":"2026-02-24T09:15:00+00:00","email":"contact@trattoria-bella.fr","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"","location":"","matched_persona":"","phone":"+33142868200","sales_navigator_profile_url":"","title":""},"signal":{"category":"Italian restaurant","confirmed_new":false,"google_maps_url":"https://www.google.com/maps?cid=10281119596374313554","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"GMB Discovery","last_signal_date":"2026-02-24","name":"New restaurants in Paris","place_id":"ChIJN1t_tDeuEmsRUsoyG83frY4","rating":4.6,"review_count":128,"siren":"912345678","type":"gmb_listing","vat":"FR40912345678"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"place_id":{"type":"string","title":"Place Id","description":"Google Maps place ID of the business","default":""},"google_maps_url":{"type":"string","title":"Google Maps Url","description":"Google Maps URL for the business listing","default":""},"category":{"type":"string","title":"Category","description":"Google Maps category of the business","default":""},"rating":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Rating","description":"Google rating (0-5); \"\" when absent","default":""},"review_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Review Count","description":"Number of Google reviews; \"\" when absent","default":""},"siren":{"type":"string","title":"Siren","description":"French SIREN identifier (when resolved)","default":""},"vat":{"type":"string","title":"Vat","description":"VAT / national company registration number (when found on the business website)","default":""},"confirmed_new":{"anyOf":[{"type":"boolean"},{"type":"string"}],"title":"Confirmed New","description":"True when keepOnlyConfirmedNew is enabled and the business was confirmed as recently registered against the SIRENE registry. \"\" when not applicable.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookGmbListingSignal","description":"Signal info for GMB Discovery (gmb_listing) — a newly-listed Google Maps business."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless a generic business email was found on the website; then a role-based contact carrying that email (no first/last name). Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookGmbLeadPayload","description":"Webhook payload for GMB Discovery (gmb_listing).\n\nCompany-only signal. All documented keys are always present, and absent\nvalues are delivered as empty strings (``\"\"``), never ``null``. ``contact``\nis the empty string ``\"\"`` unless a generic business email was found on the\nlisting's website, in which case it carries that role-based address (no\nperson name).","examples":[{"company":{"employee_count":"","employee_range":"","hq_city":"Paris","hq_country_code":"FR","industry":"Italian restaurant","linkedin_url":"","location":"Paris, France","name":"Trattoria Bella","website":"https://trattoria-bella.fr"},"contact":{"city":"","country_code":"","created_at":"2026-02-24T09:15:00+00:00","email":"contact@trattoria-bella.fr","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"","location":"","matched_persona":"","phone":"+33142868200","sales_navigator_profile_url":"","title":""},"signal":{"category":"Italian restaurant","confirmed_new":false,"google_maps_url":"https://www.google.com/maps?cid=10281119596374313554","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"GMB Discovery","last_signal_date":"2026-02-24","name":"New restaurants in Paris","place_id":"ChIJN1t_tDeuEmsRUsoyG83frY4","rating":4.6,"review_count":128,"siren":"912345678","type":"gmb_listing","vat":"FR40912345678"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/industries":{"get":{"tags":["Signals"],"summary":"List industry filter values","description":"The vocabulary accepted by `industryFilters` and `excludedIndustryFilters` on every signal that filters on a company's industry.\n\n**Input:** all optional — `search` (substring on the name), `kind` (`industry` or `category`), `category` (the industries a filter on that category accepts), `limit`.\n\n**Output:** `industries`, categories first then industries alphabetically, each with `name` (copy it verbatim — matching is exact and category names are case-sensitive), `kind`, `path` and, for a category, `industryCount`: how many industries a filter on it accepts, computed with the same rule the signals apply. Ten names (\"Manufacturing\", \"Retail\", \"Wholesale\", …) are both an industry and a category; sent as a filter they act as the category, so they are listed once, as a category. Listing a category together with industries it already covers adds nothing — the create and update responses warn when you do.","operationId":"list_signal_industries_api_v1_signals_industries_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Case-insensitive substring filter on the name.","examples":["software"],"title":"Search"},"description":"Case-insensitive substring filter on the name."},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Return only `industry` or only `category`. Omit for both.","examples":["category"],"title":"Kind"},"description":"Return only `industry` or only `category`. Omit for both."},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Return only the industries a filter on this category accepts - the list behind its `industryCount`. Exact spelling as published (category names are case-sensitive).","examples":["Manufacturing"],"title":"Category"},"description":"Return only the industries a filter on this category accepts - the list behind its `industryCount`. Exact spelling as published (category names are case-sensitive)."},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"description":"Optional cap. Omit it to get the whole vocabulary.","title":"Limit"},"description":"Optional cap. Omit it to get the whole vocabulary."}],"responses":{"200":{"description":"Every value accepted by industryFilters.","content":{"application/json":{"schema":{"properties":{"total":{"type":"integer","title":"Total","description":"Number of entries returned."},"industries":{"items":{"properties":{"name":{"type":"string","title":"Name","description":"Exact value to pass in `industryFilters` / `excludedIndustryFilters`. Copy it verbatim — matching is exact, so a near-miss like `Software development` matches nothing and the signal quietly produces no leads."},"kind":{"type":"string","title":"Kind","description":"`industry` for a single LinkedIn industry, or `category` for a broad grouping that matches every industry inside it. Filtering on a category is the easy way to cover a whole sector without listing its industries."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"For an `industry`, its position in LinkedIn's taxonomy, parents first. Null for a `category`."},"industryCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Industrycount","description":"For a `category`, how many published industries a filter on it accepts - the same rule the signals apply, so it can exceed the industries listed under it in the taxonomy. `?category=<name>` returns exactly those. Null for an `industry`."}},"type":"object","required":["name","kind"],"title":"PublicIndustry","description":"One value accepted by `industryFilters` / `excludedIndustryFilters`.","examples":[{"kind":"industry","name":"Software Development","path":"Technology, Information and Media > Technology, Information and Internet > Software Development"}]},"type":"array","title":"Industries","description":"Categories first, then industries alphabetically."}},"type":"object","required":["total","industries"],"title":"IndustriesResponse","description":"The industry vocabulary for signal filters.","examples":[{"industries":[{"industryCount":41,"kind":"category","name":"Technology and Media"},{"kind":"industry","name":"Software Development","path":"Technology, Information and Media > Technology, Information and Internet > Software Development"}],"total":443}]},"examples":{"full_list":{"summary":"Default — the complete vocabulary","value":{"total":443,"industries":[{"name":"Technology and Media","kind":"category","industryCount":41},{"name":"Software Development","kind":"industry","path":"Technology, Information and Media > Technology, Information and Internet > Software Development"}]}},"category":{"summary":"?category=Manufacturing — what that filter accepts","value":{"total":91,"industries":[{"name":"Abrasives and Nonmetallic Minerals Manufacturing","kind":"industry","path":"Manufacturing > Glass, Ceramics and Concrete Manufacturing > Abrasives and Nonmetallic Minerals Manufacturing"}]}},"search":{"summary":"Filtered with ?search=software","value":{"total":1,"industries":[{"name":"Software Development","kind":"industry","path":"Technology, Information and Media > Technology, Information and Internet > Software Development"}]}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"search","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/influencer-engagement":{"post":{"tags":["Signals"],"summary":"Create Influencer Engagement signal","description":"Get the people who engage with specific LinkedIn influencers' or thought leaders' posts — those actively reacting to or commenting on content in your space, a strong intent signal.\n\n**Input:** LinkedIn profile URLs of the influencers/creators to monitor (`linkedinUrls`); optionally specific `postUrls`, a look-back window (`postedLimit`), and `engagementTypes`, an array choosing who becomes a lead: `likes` (people who reacted), `comments` (people who commented), `poster` (the post author) and `both` (people who reacted AND commented), combinable; defaults to `[likes, comments]`.\n\n**Output:** each person selected by `engagementTypes` on those posts who matches your persona/ICP config is pushed to your `webhookUrl` as an enriched lead; non-matching engagers are filtered out.\n\n**Use cases:**\n- Influencer-audience capture — reach the engaged audience of your space's thought leaders.\n- Topic targeting — engagers on a niche influencer signal interest in that niche.","operationId":"create_company_engagement_signal_api_v1_signals_influencer_engagement_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/CompanyEngagementConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"CompanyEngagementCreate","description":"Create an Influencer Engagement signal.","examples":[{"config":{"companySizeFilters":[],"customPersonaTitles":[],"detectTechnologies":false,"engagementTypes":["likes","comments"],"excludedCompanySizeFilters":[],"excludedCompanyUrls":[],"excludedIndustryFilters":["Financial Services"],"excludedLocations":[],"excludedTitles":["Intern","Junior"],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"industryFilters":[],"linkedinUrls":["https://www.linkedin.com/in/guillaumemoubeche"],"locations":[],"maxPosts":0,"minEngagement":5,"postedLimit":"week","targetPersonas":[]},"dailyLeadLimit":50,"name":"Influencer engagement tracking","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Influencer engagement tracking","value":{"name":"Influencer engagement tracking","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"linkedinUrls":["https://www.linkedin.com/in/guillaumemoubeche"],"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":["Financial Services"],"excludedCompanySizeFilters":[],"excludedTitles":["Intern","Junior"],"excludedCompanyUrls":[],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Influencer engagement tracking","status":"active","signalTypeId":"influencer_engagement","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"linkedinUrls":["https://www.linkedin.com/in/guillaumemoubeche"],"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":["Financial Services"],"excludedCompanySizeFilters":[],"excludedTitles":["Intern","Junior"],"excludedCompanyUrls":[],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config (LinkedIn Profile URLs), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (LinkedIn Profile URLs)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["linkedin_urls"],"missing_field_labels":["LinkedIn Profile URLs"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"influencer_lead_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"Tracked LinkedIn influencer profile URL","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL that was engaged with","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment (if engagement_type is comment)","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookInfluencerSignal","description":"Signal info for influencer engagement signals (company_engagement)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookInfluencerLeadPayload","description":"Webhook payload for influencer engagement signals (company_engagement).","examples":[{"company":{"homepage_title":"StartupXYZ — AI-powered sales automation","linkedin_url":"https://linkedin.com/company/startupxyz","name":"StartupXYZ","tech_stack":["WordPress","Google Analytics","Cloudflare"],"website":"https://startupxyz.com"},"contact":{"city":"Bordeaux","country_code":"FR","created_at":"2026-02-24T14:30:00+00:00","email":"pierre.martin@techcorp.com","first_name":"Pierre","last_name":"Martin","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://linkedin.com/in/pierremartin","location":"Bordeaux, France","matched_persona":"CTO","phone":"+33699887766","sales_navigator_profile_url":"https://linkedin.com/sales/lead/ACoAAA...","title":"CTO"},"signal":{"engagement_type":"comment","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Influencer Post Reactions","last_signal_date":"2026-02-24","mention_content":"Great news! Looking forward to trying it out.","name":"Influencer Post Reactions","post_author_first_name":"Julien","post_author_last_name":"Moreau","post_content":"Just shipped our Q1 update — 3x faster onboarding and a brand-new AI-assisted workflow. Huge thanks to the team.","post_date":"2026-02-23","post_url":"https://linkedin.com/feed/update/urn:li:activity:345678","tracked_contact":"https://linkedin.com/in/influencer-profile","type":"influencer_engagement"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"Tracked LinkedIn influencer profile URL","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL that was engaged with","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment (if engagement_type is comment)","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookInfluencerSignal","description":"Signal info for influencer engagement signals (company_engagement)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookInfluencerLeadPayload","description":"Webhook payload for influencer engagement signals (company_engagement).","examples":[{"company":{"homepage_title":"StartupXYZ — AI-powered sales automation","linkedin_url":"https://linkedin.com/company/startupxyz","name":"StartupXYZ","tech_stack":["WordPress","Google Analytics","Cloudflare"],"website":"https://startupxyz.com"},"contact":{"city":"Bordeaux","country_code":"FR","created_at":"2026-02-24T14:30:00+00:00","email":"pierre.martin@techcorp.com","first_name":"Pierre","last_name":"Martin","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://linkedin.com/in/pierremartin","location":"Bordeaux, France","matched_persona":"CTO","phone":"+33699887766","sales_navigator_profile_url":"https://linkedin.com/sales/lead/ACoAAA...","title":"CTO"},"signal":{"engagement_type":"comment","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Influencer Post Reactions","last_signal_date":"2026-02-24","mention_content":"Great news! Looking forward to trying it out.","name":"Influencer Post Reactions","post_author_first_name":"Julien","post_author_last_name":"Moreau","post_content":"Just shipped our Q1 update — 3x faster onboarding and a brand-new AI-assisted workflow. Huge thanks to the team.","post_date":"2026-02-23","post_url":"https://linkedin.com/feed/update/urn:li:activity:345678","tracked_contact":"https://linkedin.com/in/influencer-profile","type":"influencer_engagement"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/job-change-watchlist":{"post":{"tags":["Signals"],"summary":"Create Job Change Watchlist signal","description":"Watch a fixed list of people and get a lead the moment one of them changes job - reach your champion in their new seat while they still have a mandate to change things.\n\nWhere the Job Changes signal DISCOVERS movers matching a persona, this one starts from your list: your champions, your buyers, your lapsed prospects.\n\n**Input:** `profiles` - the people to watch. Each entry is either a LinkedIn profile URL on its own, or an object `{url, currentTitle, currentCompany}` carrying the role you already have on file; both forms can be mixed. **Send the role when you have it.** Every check is billed, the first one included. With a role on file, the first check compares against it and reports any change straight away. With a bare URL, the first check can only report a move made in the last 6 months (it compares the current job with the one before it); anyone who moved earlier stays invisible - recorded as they stand today - and a later move is reported at the next check - one `cadenceHours` later, a week by default. A bare URL with `cadenceHours: 0` therefore only ever reports moves from the last 6 months. Then `detectionMode` (`company` - default - fires only on an employer change; `title` on a new role at the same employer; `both`), `cadenceHours` (how often each person is re-checked: 24, 168 - the default - 360, 720, 1080, 1440 or 2160; `0` checks the list once and never again), plus enrichment flags (`getEmails`, `getPhones`).\n\n**Output:** the create response carries a `watchlist` object telling you how many profiles are actually being watched and how many were rejected. From then on, each confirmed change is delivered to your `webhookUrl` as a person-lead: `signal` carries `previous_title` / `previous_company` alongside `new_title` / `new_company`, `new_job_started_on` (`\"MM/YYYY\"`, the date to test a change against - `previous_job_ended_on` differs whenever there was a gap between the two jobs), `new_job_start_month` (the same month as `\"YYYY-MM\"`, sortable) and `change_type` (`company`, `title` or `both`), while `contact` and `company` describe the person in their NEW role. The `previous_*` / `new_*` / `change_type` keys are a stable contract: present on every change, never renamed or null, `\"\"` when a value is unknown - safe to map straight into your CRM. A change is delivered once, and the new role becomes the baseline for the next check.\n\n`profiles` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response — the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/profiles`, and add or remove people with `POST` / `DELETE` on the same path, without recreating the signal.\n\n**Use cases:**\n- Follow your champions - when someone who already bought from you moves to a new company, you get a warm intro into an account with a decision-maker who has used your product before.\n- Protect renewals - when your day-to-day contact leaves an account, you learn the day it happens instead of at renewal, in time to build a relationship with their replacement.\n- Re-time a dead deal - a prospect who said no because of budget or an incumbent tool arrives somewhere new with a fresh stack and a mandate to change things; the objection left with the old job.","operationId":"create_job_change_watchlist_signal_api_v1_signals_job_change_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/JobChangeWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"JobChangeWatchlistCreate","examples":[{"config":{"cadenceHours":168,"detectionMode":"company","getEmails":true,"profiles":[{"currentCompany":"Lemlist","currentTitle":"Head of Sales","url":"https://www.linkedin.com/in/marie-dupont"},"https://www.linkedin.com/in/jean-martin"]},"dailyLeadLimit":20,"name":"My champions","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"My champions","value":{"name":"My champions","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":20,"status":"active","config":{"profiles":[{"url":"https://www.linkedin.com/in/marie-dupont","currentTitle":"Head of Sales","currentCompany":"Lemlist"},"https://www.linkedin.com/in/jean-martin"],"detectionMode":"company","cadenceHours":168,"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My champions","status":"active","signalTypeId":"job_change_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"detectionMode":"company","cadenceHours":168,"getEmails":true},"dailyLeadLimit":20,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":2,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per confirmed job change by a watched person. `contact` and `company` describe the NEW role; the previous one is on the `signal` object.","operationId":"job_change_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"previous_title":{"type":"string","title":"Previous Title","description":"Job title held before the change","default":""},"previous_company":{"type":"string","title":"Previous Company","description":"Employer before the change","default":""},"previous_company_linkedin_url":{"type":"string","title":"Previous Company Linkedin Url","description":"LinkedIn company URL of the previous employer","default":""},"previous_job_started_on":{"type":"string","title":"Previous Job Started On","description":"When the previous role started, as published (e.g. \"2022-03\")","default":""},"previous_job_ended_on":{"type":"string","title":"Previous Job Ended On","description":"When the previous role ended, as published (e.g. \"2026-04\")","default":""},"new_title":{"type":"string","title":"New Title","description":"Job title held after the change","default":""},"new_company":{"type":"string","title":"New Company","description":"Employer after the change","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When the NEW role started, as the profile publishes it: \"MM/YYYY\" (e.g. \"05/2026\"), when the profile states it. This is the date to test a change against: `previous_job_ended_on` is a different date whenever there was a gap between the two jobs. `new_job_start_month` carries the same month as \"YYYY-MM\".","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Month the NEW role started, always \"YYYY-MM\" (e.g. \"2026-05\"). Same value as `new_job_started_on`, in a sortable format. \"\" when unknown.","default":""},"change_type":{"type":"string","title":"Change Type","description":"What changed: \"company\" (moved employer), \"title\" (new role at the same employer), or \"both\".","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookJobChangeWatchlistSignal","description":"Signal info for the job_change_watchlist signal.\n\nThis signal reports a move by someone YOU put on the list, so the useful\npart is the before/after pair: ``previous_*`` is where the person was when\nyou added them, and the ``contact`` / ``company`` blocks describe where they\nare now. ``tracked_company`` is inherited and always present for shape\nparity with the other person signals, but carries no value here — the\nwatched subject is the person, not a company."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookJobChangeWatchlistPayload","description":"Webhook payload for the job_change_watchlist signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"VP Marketing"},"signal":{"change_type":"company","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Job Change Watchlist","last_signal_date":"2026-05-31","name":"My champions","new_company":"Tech Corp","new_job_start_month":"2026-05","new_job_started_on":"05/2026","new_title":"VP Marketing","previous_company":"Payfit","previous_company_linkedin_url":"https://www.linkedin.com/company/payfit/","previous_job_ended_on":"2026-04","previous_job_started_on":"2022-03","previous_title":"Head of Growth","tracked_company":"","type":"job_change_watchlist"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My champions","type":"job_change_watchlist","last_signal":"Job Change Watchlist","last_signal_date":"2026-08-04","tracked_company":"","previous_title":"Head of Growth","previous_company":"Payfit","new_title":"VP Marketing","new_company":"Doctolib","new_job_started_on":"2026-07","change_type":"company"},"contact":{"lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","created_at":"2026-08-04T09:12:00+00:00","first_name":"Marie","last_name":"Dupont","email":"marie.dupont@doctolib.fr","phone":"","title":"VP Marketing","location":"Paris, France","country_code":"FR","city":"Paris","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","sales_navigator_profile_url":"","matched_persona":""},"company":{"name":"Doctolib","website":"https://doctolib.fr","linkedin_url":"https://www.linkedin.com/company/doctolib","industry":"Software Development","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"1001-5000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"previous_title":{"type":"string","title":"Previous Title","description":"Job title held before the change","default":""},"previous_company":{"type":"string","title":"Previous Company","description":"Employer before the change","default":""},"previous_company_linkedin_url":{"type":"string","title":"Previous Company Linkedin Url","description":"LinkedIn company URL of the previous employer","default":""},"previous_job_started_on":{"type":"string","title":"Previous Job Started On","description":"When the previous role started, as published (e.g. \"2022-03\")","default":""},"previous_job_ended_on":{"type":"string","title":"Previous Job Ended On","description":"When the previous role ended, as published (e.g. \"2026-04\")","default":""},"new_title":{"type":"string","title":"New Title","description":"Job title held after the change","default":""},"new_company":{"type":"string","title":"New Company","description":"Employer after the change","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When the NEW role started, as the profile publishes it: \"MM/YYYY\" (e.g. \"05/2026\"), when the profile states it. This is the date to test a change against: `previous_job_ended_on` is a different date whenever there was a gap between the two jobs. `new_job_start_month` carries the same month as \"YYYY-MM\".","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Month the NEW role started, always \"YYYY-MM\" (e.g. \"2026-05\"). Same value as `new_job_started_on`, in a sortable format. \"\" when unknown.","default":""},"change_type":{"type":"string","title":"Change Type","description":"What changed: \"company\" (moved employer), \"title\" (new role at the same employer), or \"both\".","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookJobChangeWatchlistSignal","description":"Signal info for the job_change_watchlist signal.\n\nThis signal reports a move by someone YOU put on the list, so the useful\npart is the before/after pair: ``previous_*`` is where the person was when\nyou added them, and the ``contact`` / ``company`` blocks describe where they\nare now. ``tracked_company`` is inherited and always present for shape\nparity with the other person signals, but carries no value here — the\nwatched subject is the person, not a company."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookJobChangeWatchlistPayload","description":"Webhook payload for the job_change_watchlist signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"VP Marketing"},"signal":{"change_type":"company","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Job Change Watchlist","last_signal_date":"2026-05-31","name":"My champions","new_company":"Tech Corp","new_job_start_month":"2026-05","new_job_started_on":"05/2026","new_title":"VP Marketing","previous_company":"Payfit","previous_company_linkedin_url":"https://www.linkedin.com/company/payfit/","previous_job_ended_on":"2026-04","previous_job_started_on":"2022-03","previous_title":"Head of Growth","tracked_company":"","type":"job_change_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/job-changes":{"post":{"tags":["Signals"],"summary":"Create Job Changes signal","description":"Track when the decision-makers you care about change jobs — get notified when someone matching your target personas starts a new position at a company in your ICP, and receive their enriched profile at your `webhookUrl`.\n\n**Input:** `name`, `webhookUrl`, and a `config` object with: `jobTitles` (preset personas from GET /api/v1/personas, e.g. \"CTO\", \"Sales Director\"), `customTitles` (your own titles), `excludedTitles`, `companySizeFilters` / `excludedCompanySizeFilters`, `locations` / `excludedLocations`, `industryFilters` / `excludedIndustryFilters` (values from GET /api/v1/signals/industries), `companyTypeFilters`, `excludedCompanyUrls`, `maxJobAgeDays` (how recent the new position must be; minimum and default 180 days), and optional enrichments (`getEmails`, `getPhones`, `getSireneData`, `detectTechnologies`, `getHomepageContent`). Top-level `dailyLeadLimit` (1–999,999) and `status` (draft/active/paused, default draft) complete the request.\n\n**How the filters are applied** — read this before sizing a list:\n- **Titles are matched by meaning, not as text.** `jobTitles` and `customTitles` form ONE list; a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies a \"Sales Director\" target), and a role at that level OR ABOVE qualifies: a Director target accepts VPs and heads of the function and refuses a plain Manager; a Manager target also accepts Directors. A custom title carries the level its own words state; one with no level word accepts every level. `excludedTitles` is a substring check applied first.\n- **Company size** is judged on the NEW employer: its declared band OR its employee count must fall in `companySizeFilters` (a count within 10% of a band edge counts for both bands; a company declaring 501+ employees is never placed in a smaller band by a low count). Exclusions are strict on either value. A company whose size cannot be determined is delivered only when your selection includes a band under 51 employees.\n- **Location is the PERSON's profile location**, not the company's headquarters. One matching entry in `locations` is enough; a profile with no location is dropped when `locations` is set; a profile that states only a country does not match a city or region entry. `locationFilter` is not used — send `locations`.\n- **Industry** is an exact-name match on the new employer's industry, except that a CATEGORY name accepts every industry inside it — and ten names (\"Manufacturing\", \"Retail\", \"Wholesale\", …) are both an industry and a category and are applied as the category. GET /api/v1/signals/industries gives each category's real `industryCount` and `?category=` lists its members. A value outside that list matches nothing.\n- **Recency:** a position is delivered up to `maxJobAgeDays` days after its start date, never less than 180; a smaller value is applied as 180.\n\n**Output:** `201 Created` returns the signal, its stored `config`, `applied` (the settings in force where they differ from `config`) and `warnings` (filter values that are probably not what you meant — a category sent with its own industries, an unknown industry). Each person matching your personas and filters who recently started a new job is pushed to your `webhookUrl` as a JSON lead payload (`WebhookPersonLeadPayload`): a `signal` object (id, name, type, human-readable label, detection date, plus the move itself — `previous_title`, `previous_company`, `previous_company_linkedin_url`, `previous_job_started_on`, `previous_job_ended_on`, `new_title`, `new_company`, `new_job_started_on` (`\"MM/YYYY\"`), `new_job_start_month` (the same month as `\"YYYY-MM\"`, sortable) and `change_type`: `company`, `title` or `both`. Test the freshness of a change against `new_job_started_on` / `new_job_start_month` — `previous_job_ended_on` is a different date whenever there was a gap between the two jobs. These ten `signal` keys are a stable contract: present on every job-change lead, never renamed or null, `\"\"` when a value is unknown — safe to map straight into your CRM), a `contact` object (first/last name, title, location, LinkedIn and Sales Navigator profile URLs, matched persona, and email/phone when enrichment is enabled), and a `company` object (name, website, LinkedIn URL — plus detected tech stack and homepage title/description when those enrichments are on). Fields that aren't available are returned as empty strings.\n\n**Use cases:**\n- New-buyer outreach — reach decision-makers in their first 90 days, when they re-evaluate tools and vendors.\n- Champion tracking — follow past champions to their new company for a warm re-intro.\n- Territory alerts — notify the owning rep when a target persona lands at an account.","operationId":"create_job_changes_signal_api_v1_signals_job_changes_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobChangesCreate"},"examples":{"example1":{"summary":"Decision makers changing jobs","value":{"name":"Decision makers changing jobs","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"jobTitles":["CTO","Product Director"],"customTitles":["Head of Platform"],"locations":["France"],"excludedLocations":[],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Decision makers changing jobs","status":"active","signalTypeId":"job_changes","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"companySizeFilters":["51-200","201-500","501-1000"],"jobTitles":["CTO","Product Director"],"customTitles":["Head of Platform"],"locations":["France"],"excludedLocations":[],"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedTitles":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{"allowUnknownCompanySize":false},"warnings":[{"code":"UNKNOWN_SIZE_NOT_ACCEPTED","severity":"info","field":"allowUnknownCompanySize","message":"Companies whose size cannot be determined are accepted only when the size selection includes a band under 51 employees (\"Self-employed\", \"1-10\", \"11-50\"). This selection does not, so such companies are not delivered.","values":[]}]}}}},"400":{"description":"Invalid request: missing required config (Job Title Presets), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (Job Title Presets)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["job_titles"],"missing_field_labels":["Job Title Presets"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_job_changes","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"previous_title":{"type":"string","title":"Previous Title","description":"Job title held before the change","default":""},"previous_company":{"type":"string","title":"Previous Company","description":"Employer before the change","default":""},"previous_company_linkedin_url":{"type":"string","title":"Previous Company Linkedin Url","description":"LinkedIn company URL of the previous employer","default":""},"previous_job_started_on":{"type":"string","title":"Previous Job Started On","description":"When the previous role started, as published (e.g. \"2022-03\")","default":""},"previous_job_ended_on":{"type":"string","title":"Previous Job Ended On","description":"When the previous role ended, as published (e.g. \"2026-04\")","default":""},"new_title":{"type":"string","title":"New Title","description":"Job title held after the change","default":""},"new_company":{"type":"string","title":"New Company","description":"Employer after the change","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When the NEW role started, as the profile publishes it: \"MM/YYYY\" (e.g. \"05/2026\"). This is the date to test a change against: `previous_job_ended_on` is a different date whenever there was a gap between the two jobs. `new_job_start_month` carries the same month as \"YYYY-MM\".","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Month the NEW role started, always \"YYYY-MM\" (e.g. \"2026-05\"). Same value as `new_job_started_on`, in a sortable format. \"\" when unknown.","default":""},"change_type":{"type":"string","title":"Change Type","description":"What changed: \"company\" (moved employer), \"title\" (new role at the same employer), or \"both\". \"\" when the two could not be compared.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookJobChangesSignal","description":"Signal info for the job_changes signal.\n\nThe ``contact`` / ``company`` blocks describe where the person is NOW; these\nfields describe where they came from. The pair is the signal — without the\nprevious employer the receiver cannot tell a move between companies from a\npromotion in place, and the two call for different outreach.\n\nPopulated from the position history on the extracted profile. When the\nprofile carries no position history the fields are ``\"\"``, as\neverywhere else — the lead is still delivered."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookJobChangesPayload","description":"Webhook payload for the job_changes signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Marketing Director","phone":"","sales_navigator_profile_url":"","title":"Marketing & Communication Director"},"signal":{"change_type":"company","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Job Change","last_signal_date":"2026-05-31","name":"New GTM leaders in my ICP","new_company":"Tech Corp","new_job_start_month":"2026-05","new_job_started_on":"05/2026","new_title":"Marketing & Communication Director","previous_company":"Payfit","previous_company_linkedin_url":"https://www.linkedin.com/company/payfit/","previous_job_ended_on":"2026-04","previous_job_started_on":"2022-03","previous_title":"Head of Growth","tracked_company":"https://www.linkedin.com/company/techcorp/","type":"job_changes"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"previous_title":{"type":"string","title":"Previous Title","description":"Job title held before the change","default":""},"previous_company":{"type":"string","title":"Previous Company","description":"Employer before the change","default":""},"previous_company_linkedin_url":{"type":"string","title":"Previous Company Linkedin Url","description":"LinkedIn company URL of the previous employer","default":""},"previous_job_started_on":{"type":"string","title":"Previous Job Started On","description":"When the previous role started, as published (e.g. \"2022-03\")","default":""},"previous_job_ended_on":{"type":"string","title":"Previous Job Ended On","description":"When the previous role ended, as published (e.g. \"2026-04\")","default":""},"new_title":{"type":"string","title":"New Title","description":"Job title held after the change","default":""},"new_company":{"type":"string","title":"New Company","description":"Employer after the change","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When the NEW role started, as the profile publishes it: \"MM/YYYY\" (e.g. \"05/2026\"). This is the date to test a change against: `previous_job_ended_on` is a different date whenever there was a gap between the two jobs. `new_job_start_month` carries the same month as \"YYYY-MM\".","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Month the NEW role started, always \"YYYY-MM\" (e.g. \"2026-05\"). Same value as `new_job_started_on`, in a sortable format. \"\" when unknown.","default":""},"change_type":{"type":"string","title":"Change Type","description":"What changed: \"company\" (moved employer), \"title\" (new role at the same employer), or \"both\". \"\" when the two could not be compared.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookJobChangesSignal","description":"Signal info for the job_changes signal.\n\nThe ``contact`` / ``company`` blocks describe where the person is NOW; these\nfields describe where they came from. The pair is the signal — without the\nprevious employer the receiver cannot tell a move between companies from a\npromotion in place, and the two call for different outreach.\n\nPopulated from the position history on the extracted profile. When the\nprofile carries no position history the fields are ``\"\"``, as\neverywhere else — the lead is still delivered."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookJobChangesPayload","description":"Webhook payload for the job_changes signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Marketing Director","phone":"","sales_navigator_profile_url":"","title":"Marketing & Communication Director"},"signal":{"change_type":"company","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Job Change","last_signal_date":"2026-05-31","name":"New GTM leaders in my ICP","new_company":"Tech Corp","new_job_start_month":"2026-05","new_job_started_on":"05/2026","new_title":"Marketing & Communication Director","previous_company":"Payfit","previous_company_linkedin_url":"https://www.linkedin.com/company/payfit/","previous_job_ended_on":"2026-04","previous_job_started_on":"2022-03","previous_title":"Head of Growth","tracked_company":"https://www.linkedin.com/company/techcorp/","type":"job_changes"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/job-offers":{"post":{"tags":["Signals"],"summary":"Create Job Offers signal","description":"Automatically detect new job postings that match your hiring criteria — filtered by job title, description keywords, location, and company profile — and receive each match on your webhook as it is found. Optionally enrich each hiring company with email, phone, French SIRENE, technology-stack, or homepage data, and target specific decision-maker roles at the company.\n\n**Input:** signal `name`, `webhookUrl`, and a `config` object with job filters (`jobTitleInclude`, `jobTitleExclude`, `jobTitleIncludeAll`, `jobDescriptionInclude`, `jobDescriptionExclude`, `jobDescriptionIncludeAll`, or advanced boolean `jobTitleQuery` / `jobDescriptionQuery`, `locations` — optional, empty means worldwide — `companySizeFilters`, `publishedDate`), exclusions (`excludedLocations`, `excludedCompanySizeFilters`, `companyIndustryExcluded`, `excludedWebsites`), enrichment flags (`getEmails`, `getPhones`, `getSireneData`, `detectTechnologies`, `getHomepageContent`), and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `customPersonaTitles`, `excludedTitles`, `personaExportMode`, `maxLeadsPerCompany` — 1-50 contacts per company; **omit it and the default is 10% of company headcount, minimum 1** — `personaLocations`, `personaExcludedLocations`, `companyOnlyWhenContactsRefused` — default false; on, a company whose candidates were all filtered out by your persona/location/size settings is still delivered, with no contact, instead of nothing). Plus `dailyLeadLimit` (1–999,999, default 100) and initial `status` (`draft` | `active` | `paused`, default `draft`).\n\n**Output:** `201 Created` returns the signal (`id`, `name`, `status`, `signalTypeId`, `webhookUrl`, `config`, `dailyLeadLimit`, `leadsToday`, `leadsTotal`, `duplicateHandling`, `createdAt`, `updatedAt`, `lastLeadAt`). Each matching job is then delivered to your `webhookUrl` as a JSON payload with a `signal` block (job URL, title, description, location, publication date, source, matched keywords), a `company` block (name, website, LinkedIn URL, industry, location, employee count and range), and a `contact` field. `contact` is the empty string `\"\"` (never null) unless persona targeting is enabled; when enabled it is a contact object (first/last name, job title, email, phone, LinkedIn profile URL, Sales Navigator URL, location, and the matched persona name). Enrichment and persona fields are empty strings when unavailable. **Note on `locations`:** it is optional — omit it or send an empty list to search **worldwide**. Multiple locations are combined with OR, so each one you add widens the search. Pass names (`\"France\"`), not ids; an unrecognised name returns 400 `INVALID_LOCATION`. Worldwide signals can match a lot more, so size `dailyLeadLimit` accordingly.\n\n**Use cases:**\n- Hiring = budget — a company hiring for a function is investing in it; pitch the enabling tool for that team.\n- Role-based targeting — a 'Head of X' opening → pitch X solutions to that department.\n- Pre-arrival outreach — reach the hiring manager before the new hire starts.","operationId":"create_job_offers_signal_api_v1_signals_job_offers_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobOffersCreate"},"examples":{"example1":{"summary":"Senior engineer hires in SaaS","value":{"name":"Senior engineer hires in SaaS","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":100,"status":"active","config":{"getEmails":false,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"jobTitleInclude":["Senior","Lead","Staff"],"jobTitleExclude":["Intern"],"jobTitleIncludeAll":false,"jobDescriptionInclude":["Python","React"],"jobDescriptionExclude":[],"jobDescriptionIncludeAll":false,"locations":["Paris, France","Remote"],"companySizeFilters":["51-200","201-500"],"excludedWebsites":["acme.com"],"publishedDate":"7d","enablePersonaTargeting":false,"targetPersonas":[],"customPersonaTitles":[],"personaExportMode":"top_ranked","personaLocations":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Senior engineer hires in SaaS","status":"active","signalTypeId":"job_offers","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":false,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"jobTitleInclude":["Senior","Lead","Staff"],"jobTitleExclude":["Intern"],"jobTitleIncludeAll":false,"jobDescriptionInclude":["Python","React"],"jobDescriptionExclude":[],"jobDescriptionIncludeAll":false,"locations":["Paris, France","Remote"],"companySizeFilters":["51-200","201-500"],"excludedWebsites":["acme.com"],"publishedDate":"7d","enablePersonaTargeting":false,"targetPersonas":[],"customPersonaTitles":[],"personaExportMode":"top_ranked","personaLocations":[]},"dailyLeadLimit":100,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: an unrecognized location filter","content":{"application/json":{"examples":{"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching job is found. `contact` is null unless persona targeting is enabled.","operationId":"job_lead_webhook_job_offers","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookJobOffersPayload","description":"Webhook payload for the job_offers signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Probable Hiring Manager","phone":"","sales_navigator_profile_url":"","title":"Talent Acquisition Manager"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-28","job_offer_description":"We are hiring a Senior AE to own the full enterprise sales cycle...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-28","job_offer_source":"LinkedIn","job_offer_title":"Senior Account Executive","job_offer_url":"https://www.linkedin.com/jobs/view/4440008093","last_signal":"Job Offer","last_signal_date":"2026-05-31","matched_keywords":"Account Executive,Sales","name":"SaaS companies hiring AEs","type":"job_offers"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookJobOffersPayload","description":"Webhook payload for the job_offers signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Probable Hiring Manager","phone":"","sales_navigator_profile_url":"","title":"Talent Acquisition Manager"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-28","job_offer_description":"We are hiring a Senior AE to own the full enterprise sales cycle...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-28","job_offer_source":"LinkedIn","job_offer_title":"Senior Account Executive","job_offer_url":"https://www.linkedin.com/jobs/view/4440008093","last_signal":"Job Offer","last_signal_date":"2026-05-31","matched_keywords":"Account Executive,Sales","name":"SaaS companies hiring AEs","type":"job_offers"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/job-offers-watchlist":{"post":{"tags":["Signals"],"summary":"Create Job Offers Watchlist signal","description":"Watch a fixed list of companies and get their new job postings as leads - reach the hiring decision-maker the day a role opens at an account you already care about.\n\nWhere the Job Offers signal DISCOVERS companies from filters, this one starts from your list: your target accounts, your customers, or your competitors.\n\n**Input:** `companies` (names, domains or LinkedIn company URLs, or objects `{name, domain, linkedinUrl}` carrying all three - send the LinkedIn URL whenever you have it, it identifies the company exactly where a name cannot separate two companies sharing one; failing that a name matches more reliably than a domain), `maxJobsPerCompanyPerDay` (default 3; total daily volume is roughly this x the number of companies watched), `cadenceHours` (default 24), `jobTitleInclude` / `jobTitleExclude`, `firstRunLookbackDays` (default 30 - bounds the first check of a newly added company so it does not deliver its whole posting history at once), and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`, `companyOnlyWhenContactsRefused` - default false, deliver the company alone, no contact, when people were found there but every one was filtered out by your persona/location/size settings, instead of nothing), plus enrichment flags (`getEmails`, `getPhones`).\n\n**Output:** each new posting at a watched company is pushed to your `webhookUrl`. With persona targeting off you receive one company-level lead per posting (`contact` empty); with it on you receive the hiring decision-makers as person-leads. A posting is delivered ONCE - later checks only surface roles newer than what you have already received.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, which is also the only place that tells you which companies were actually matched to an employer, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Account-based hiring alerts - the day a target account opens a role, reach the hiring manager while the need is fresh and no vendor has been chosen.\n- Expansion triggers in your customer base - watch existing customers and treat a new role on a team you sell to as a signal that budget and headcount just moved.\n- Competitor headcount watch - track competitors' postings to see which teams they are building, and time your differentiation play accordingly.","operationId":"create_job_offers_watchlist_signal_api_v1_signals_job_offers_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/JobOffersWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"JobOffersWatchlistCreate","examples":[{"config":{"cadenceHours":24,"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"jobTitleInclude":["Account Executive","Sales"],"maxJobsPerCompanyPerDay":3,"targetPersonas":["Head of Sales"]},"dailyLeadLimit":30,"name":"Hiring at my target accounts","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Hiring at my target accounts","value":{"name":"Hiring at my target accounts","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":30,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"lemlist"],"maxJobsPerCompanyPerDay":3,"cadenceHours":24,"jobTitleInclude":["Account Executive","Sales"],"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Hiring at my target accounts","status":"active","signalTypeId":"job_offers_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"maxJobsPerCompanyPerDay":3,"cadenceHours":24,"jobTitleInclude":["Account Executive","Sales"],"enablePersonaTargeting":true,"targetPersonas":["Head of Sales"],"getEmails":true},"dailyLeadLimit":30,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent for each new job posting at a watched company, capped by `maxJobsPerCompanyPerDay`.","operationId":"job_offers_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookJobOffersPayload","description":"Webhook payload for the job_offers signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Probable Hiring Manager","phone":"","sales_navigator_profile_url":"","title":"Talent Acquisition Manager"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-28","job_offer_description":"We are hiring a Senior AE to own the full enterprise sales cycle...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-28","job_offer_source":"LinkedIn","job_offer_title":"Senior Account Executive","job_offer_url":"https://www.linkedin.com/jobs/view/4440008093","last_signal":"Job Offer","last_signal_date":"2026-05-31","matched_keywords":"Account Executive,Sales","name":"SaaS companies hiring AEs","type":"job_offers"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Hiring at my target accounts","type":"job_offers_watchlist","last_signal":"Job Offers Watchlist","last_signal_date":"2026-08-04","job_offer_url":"https://www.welcometothejungle.com/companies/lemlist/jobs/account-executive_paris","job_offer_title":"Account Executive","job_offer_location":"Paris, Ile-de-France, France","job_offer_description":"We are looking for an Account Executive to join our sales team...","job_offer_date":"2026-08-03","job_offer_source":"wttj","matched_keywords":"Account Executive"},"contact":"","company":{"name":"lemlist","website":"https://lemlist.com","linkedin_url":"https://www.linkedin.com/company/lemlist","industry":"Software Development","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"51-200"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookJobOffersPayload","description":"Webhook payload for the job_offers signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Probable Hiring Manager","phone":"","sales_navigator_profile_url":"","title":"Talent Acquisition Manager"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-28","job_offer_description":"We are hiring a Senior AE to own the full enterprise sales cycle...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-28","job_offer_source":"LinkedIn","job_offer_title":"Senior Account Executive","job_offer_url":"https://www.linkedin.com/jobs/view/4440008093","last_signal":"Job Offer","last_signal_date":"2026-05-31","matched_keywords":"Account Executive,Sales","name":"SaaS companies hiring AEs","type":"job_offers"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/job-sectors":{"get":{"tags":["Signals"],"summary":"List job sectors (deprecated — use /signals/industries)","description":"**Legacy.** The job signals (Job Offers, Republished Job Offers, Recruitment Campaign) now take LinkedIn industry names in `industryFilters` and `companyIndustryExcluded`, exactly like every other signal — call `GET /api/v1/signals/industries` instead. This endpoint remains so that integrations built against the older sector vocabulary keep working: a sector id listed here is still accepted and applied unchanged.\n\n**Input:** `search` (optional query parameter — case-insensitive substring on the sector name or its label, e.g. `consult`) and `limit` (optional, 1-500, defaults to 100).\n\n**Output:** `total` (number of sectors matched) and `sectors` — each with `name` (the exact string to submit), `category` (the broad family it belongs to) and `subCategory` (its readable label). `companyCount` is deprecated and always null.\n\nA common mistake: putting a *company* name (`Accenture`, `Capgemini`) in `companyIndustryExcluded`. That field takes industries only — to exclude named companies, list their domains in `excludedWebsites` instead.","operationId":"list_job_sectors_api_v1_signals_job_sectors_get","deprecated":true,"security":[{"BearerAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Case-insensitive substring filter on the sector name.","examples":["staff"],"title":"Search"},"description":"Case-insensitive substring filter on the sector name."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Maximum sectors to return. Defaults to 100.","default":100,"title":"Limit"},"description":"Maximum sectors to return. Defaults to 100."}],"responses":{"200":{"description":"Sectors ordered by company count, largest first.","content":{"application/json":{"schema":{"properties":{"total":{"type":"integer","title":"Total","description":"Number of sectors returned."},"sectors":{"items":{"properties":{"name":{"type":"string","title":"Name","description":"Exact value to pass in `industryFilters` / `companyIndustryExcluded`."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Broad family this sector belongs to, e.g. 'Consulting / Audit'."},"subCategory":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subcategory","description":"The sector's readable label within its category."},"companyCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companycount","description":"Deprecated. Always null; volume counts are no longer published."}},"type":"object","required":["name"],"title":"JobSector","description":"One sector accepted by the job signals' sector filters.","examples":[{"category":"Consulting / Audit","name":"consulting","subCategory":"Consulting"}]},"type":"array","title":"Sectors","description":"Sectors ordered by company count, largest first."}},"type":"object","required":["total","sectors"],"title":"JobSectorsResponse","description":"The sector vocabulary for job-signal filters.","examples":[{"sectors":[{"companyCount":13708668,"name":"consulting"},{"companyCount":13190231,"name":"recruiting"},{"companyCount":5192754,"name":"healthcare"}],"total":3}]},"examples":{"top_sectors":{"summary":"First few sectors","value":{"total":501,"sectors":[{"name":"consulting","companyCount":13708668},{"name":"recruiting","companyCount":13190231},{"name":"healthcare","companyCount":5192754}]}},"search":{"summary":"Filtered with ?search=staff","value":{"total":2,"sectors":[{"name":"staffing","companyCount":1204553},{"name":"staffing agency","companyCount":41220}]}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"search","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/mergers-acquisitions":{"post":{"tags":["Signals"],"summary":"Create Mergers & Acquisitions signal","description":"Track companies making acquisitions or merging in your target markets — surface the acquiring company as a sales opportunity the moment a deal is announced, with optional enrichment of its key decision-makers. Acquisitions often trigger budget, integration, and new-tooling needs you can act on early.\n\n**Input:** deal types (`dealTypes`: acquisition, merger, leveraged_buyout, management_buyout); minimum deal size (`minAmount`, in USD); recency window (`announcedPeriod`: 24h, 7d, 30d, 60d, 90d, 12m, or custom); ICP filters — applied to the acquiring company — (`industryFilters`, `companySizeFilters`, `hqLocations`, each with an `excluded*` counterpart); optional persona targeting to reach executives at the acquirer (`enablePersonaTargeting`, `targetPersonas`, `customPersonaTitles`); optional enrichment flags (`getEmails`, `getPhones`, `getSireneData`, `detectTechnologies`, `getHomepageContent`).\n\n**Output:** each qualifying deal is pushed to your `webhookUrl` as it's announced, carrying both sides of the transaction — acquirer and acquired-company names, websites, industries, and locations — plus the deal type, deal price in USD (with currency), announcement date, and an AI-generated article summary and acquisition rationale. The lead's company is the acquirer. If persona targeting is enabled, matched executives at the acquirer are attached as the contact; otherwise contact is empty. Requested enrichments are included when available.\n\n**Use cases:**\n- Consolidation plays — post-M&A, tools and systems get re-evaluated and consolidated; pitch the platform that wins.\n- Integration services — offer migration / integration help during the merge.","operationId":"create_mergers_acquisitions_signal_api_v1_signals_mergers_acquisitions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergersAcquisitionsCreate"},"examples":{"example1":{"summary":"SaaS acquisitions in Europe","value":{"name":"SaaS acquisitions in Europe","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"dealTypes":["acquisition","merger"],"announcedPeriod":"30d","minAmount":500000,"industryFilters":["Software Development","IT Services and IT Consulting"],"companySizeFilters":["51-200","201-500"],"hqLocations":["France","United Kingdom"],"enablePersonaTargeting":true,"targetPersonas":["CEO","Finance Director"],"customPersonaTitles":["Chief Strategy Officer"],"personaExportMode":"top_ranked","personaLocations":[]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"SaaS acquisitions in Europe","status":"active","signalTypeId":"mergers_acquisitions","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"dealTypes":["acquisition","merger"],"announcedPeriod":"30d","minAmount":500000,"industryFilters":["Software Development","IT Services and IT Consulting"],"companySizeFilters":["51-200","201-500"],"hqLocations":["France","United Kingdom"],"enablePersonaTargeting":true,"targetPersonas":["CEO","Finance Director"],"customPersonaTitles":["Chief Strategy Officer"],"personaExportMode":"top_ranked","personaLocations":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a merger or acquisition is detected. `contact` is null unless persona targeting is enabled.","operationId":"ma_webhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookMergersAcquisitionsPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookMergersAcquisitionsPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/mergers-acquisitions-watchlist":{"post":{"tags":["Signals"],"summary":"Create M&A Watchlist signal","description":"Get told when a company on YOUR list is acquired, or acquires someone. Being bought puts an account's whole stack under review; buying means budget and a system to integrate. Both are openings, and you choose which to hear about with `watchSide`.\n\nWhere the M&A signal always prospects the acquirer, here the lead is always YOUR company - whichever side of the deal it was on - and `signal.deal_role` tells you which. There is deliberately no company-size, location or industry filter: you named the companies, which answers that far more precisely than an ICP could, and re-filtering your own list could only drop accounts you asked us to watch.\n\n**Input:** `companies` (names, domains or LinkedIn company URLs), `watchSide` (`acquiree` / `acquirer` / `both`, default `both`), `dealTypes`, `minAmount` (USD), `announcedPeriod` (default `30d`), plus optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`).\n\n**Output:** each qualifying deal is delivered to your `webhookUrl`. A deal between two watched companies delivers BOTH, once each, distinguished by `signal.deal_role`.\n\n**Persona targeting changes WHAT you receive; it does not add to it.** Left off, a deal delivers one company-level lead carrying no contact. Turned on, that company lead is REPLACED by one lead per matching person at the company - so a deal that would have sent one payload can send several, or none at all if nobody matches. `maxLeadsPerCompany` caps how many; `personaExportMode` chooses between the best-ranked contacts (the default) and every match. Persona leads are billed per person found, not per deal.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Your champion got bought - the acquiree's stack goes under review within weeks; reach them while it is still their decision.\n- Your account went shopping - an acquirer has budget and a freshly inherited system to integrate, which is a services and tooling opening.\n- Protect the base - watch your own customers so you learn about a deal from us rather than from a churn notice.","operationId":"create_mergers_acquisitions_watchlist_signal_api_v1_signals_mergers_acquisitions_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/MergersAcquisitionsWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"MergersAcquisitionsWatchlistCreate","examples":[{"config":{"announcedPeriod":"30d","companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"}],"dealTypes":["acquisition"],"getEmails":true,"watchSide":"both"},"dailyLeadLimit":20,"name":"M&A at my accounts","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"M&A at my accounts","value":{"name":"M&A at my accounts","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":20,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"}],"watchSide":"both","dealTypes":["acquisition"],"announcedPeriod":"30d","getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"M&A at my accounts","status":"active","signalTypeId":"mergers_acquisitions_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"watchSide":"both","dealTypes":["acquisition"],"announcedPeriod":"30d","getEmails":true},"dailyLeadLimit":20,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":2,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent for each qualifying deal involving a watched company. `signal.deal_role` says which side yours was on.","operationId":"mergers_acquisitions_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"acquiree_name":{"type":"string","title":"Acquiree Name","description":"Acquired company name","default":""},"acquiree_website":{"type":"string","title":"Acquiree Website","description":"Acquired company website","default":""},"acquiree_industries":{"type":"string","title":"Acquiree Industries","description":"Acquired company industries","default":""},"acquiree_location":{"type":"string","title":"Acquiree Location","description":"Acquired company HQ location","default":""},"acquiree_crunchbase_url":{"type":"string","title":"Acquiree Crunchbase Url","description":"Acquired company public profile URL","default":""},"acquirer_name":{"type":"string","title":"Acquirer Name","description":"Acquiring company name","default":""},"acquirer_website":{"type":"string","title":"Acquirer Website","description":"Acquiring company website","default":""},"acquirer_industries":{"type":"string","title":"Acquirer Industries","description":"Acquiring company industries","default":""},"acquirer_location":{"type":"string","title":"Acquirer Location","description":"Acquiring company HQ location","default":""},"acquirer_crunchbase_url":{"type":"string","title":"Acquirer Crunchbase Url","description":"Acquiring company public profile URL","default":""},"acquisition_type":{"type":"string","title":"Acquisition Type","description":"Deal type (e.g. \"acquisition\", \"merger\")","default":""},"deal_price_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Deal Price Usd","description":"Deal price in USD; \"\" when absent","default":""},"deal_price_currency":{"type":"string","title":"Deal Price Currency","description":"Deal price currency code","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD)","default":""},"article_summary":{"type":"string","title":"Article Summary","description":"AI-generated summary of the M&A deal article","default":""},"article_acquisition_rationale":{"type":"string","title":"Article Acquisition Rationale","description":"AI-extracted rationale for the acquisition","default":""},"article_source_url":{"type":"string","title":"Article Source Url","description":"URL of the source article about the deal","default":""},"deal_role":{"type":"string","title":"Deal Role","description":"Which side of the deal YOUR company was on: \"acquiree\" (it was bought) or \"acquirer\" (it bought someone). The lead is always your watched company. A deal between two watched companies is delivered twice, once per role.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookMergersAcquisitionsWatchlistSignal","description":"Signal info for a deal involving a WATCHED company.\n\nAdds the one field the open M&A signal has no concept of: which side of the\ndeal the watched company was on. The open signal always prospects the\nacquirer, so it never needs to say."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookMergersAcquisitionsWatchlistPayload","description":"Webhook payload for mergers_acquisitions_watchlist.\n\nAll documented keys are always present; absent values are delivered as empty\nstrings (``\"\"``), never ``null``.","examples":[{"company":{"employee_range":"501-1000","hq_city":"Paris","hq_country_code":"FR","industry":"Software","linkedin_url":"https://www.linkedin.com/company/payfit","location":"Paris, France","name":"Payfit","website":"https://payfit.com"},"contact":"","signal":{"acquiree_name":"Payfit","acquirer_name":"Visma","acquisition_type":"acquisition","announcement_date":"2026-08-11","deal_role":"acquiree","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","last_signal":"Watched Company Deal","last_signal_date":"2026-08-13","name":"M&A at my accounts","type":"mergers_acquisitions_watchlist"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"My accounts","type":"mergers_acquisitions_watchlist","last_signal":"Watched Company Deal","last_signal_date":"2026-08-13","deal_role":"acquiree","acquisition_type":"acquisition","acquiree_name":"Payfit","acquirer_name":"Visma","price_usd":0,"announcement_date":"2026-08-11","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":""},"contact":"","company":{"name":"Payfit","website":"https://payfit.com","linkedin_url":"https://www.linkedin.com/company/payfit","industry":"Software","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"501-1000"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"acquiree_name":{"type":"string","title":"Acquiree Name","description":"Acquired company name","default":""},"acquiree_website":{"type":"string","title":"Acquiree Website","description":"Acquired company website","default":""},"acquiree_industries":{"type":"string","title":"Acquiree Industries","description":"Acquired company industries","default":""},"acquiree_location":{"type":"string","title":"Acquiree Location","description":"Acquired company HQ location","default":""},"acquiree_crunchbase_url":{"type":"string","title":"Acquiree Crunchbase Url","description":"Acquired company public profile URL","default":""},"acquirer_name":{"type":"string","title":"Acquirer Name","description":"Acquiring company name","default":""},"acquirer_website":{"type":"string","title":"Acquirer Website","description":"Acquiring company website","default":""},"acquirer_industries":{"type":"string","title":"Acquirer Industries","description":"Acquiring company industries","default":""},"acquirer_location":{"type":"string","title":"Acquirer Location","description":"Acquiring company HQ location","default":""},"acquirer_crunchbase_url":{"type":"string","title":"Acquirer Crunchbase Url","description":"Acquiring company public profile URL","default":""},"acquisition_type":{"type":"string","title":"Acquisition Type","description":"Deal type (e.g. \"acquisition\", \"merger\")","default":""},"deal_price_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Deal Price Usd","description":"Deal price in USD; \"\" when absent","default":""},"deal_price_currency":{"type":"string","title":"Deal Price Currency","description":"Deal price currency code","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD)","default":""},"article_summary":{"type":"string","title":"Article Summary","description":"AI-generated summary of the M&A deal article","default":""},"article_acquisition_rationale":{"type":"string","title":"Article Acquisition Rationale","description":"AI-extracted rationale for the acquisition","default":""},"article_source_url":{"type":"string","title":"Article Source Url","description":"URL of the source article about the deal","default":""},"deal_role":{"type":"string","title":"Deal Role","description":"Which side of the deal YOUR company was on: \"acquiree\" (it was bought) or \"acquirer\" (it bought someone). The lead is always your watched company. A deal between two watched companies is delivered twice, once per role.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookMergersAcquisitionsWatchlistSignal","description":"Signal info for a deal involving a WATCHED company.\n\nAdds the one field the open M&A signal has no concept of: which side of the\ndeal the watched company was on. The open signal always prospects the\nacquirer, so it never needs to say."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookMergersAcquisitionsWatchlistPayload","description":"Webhook payload for mergers_acquisitions_watchlist.\n\nAll documented keys are always present; absent values are delivered as empty\nstrings (``\"\"``), never ``null``.","examples":[{"company":{"employee_range":"501-1000","hq_city":"Paris","hq_country_code":"FR","industry":"Software","linkedin_url":"https://www.linkedin.com/company/payfit","location":"Paris, France","name":"Payfit","website":"https://payfit.com"},"contact":"","signal":{"acquiree_name":"Payfit","acquirer_name":"Visma","acquisition_type":"acquisition","announcement_date":"2026-08-11","deal_role":"acquiree","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","last_signal":"Watched Company Deal","last_signal_date":"2026-08-13","name":"M&A at my accounts","type":"mergers_acquisitions_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/mutual-connections":{"post":{"tags":["Signals"],"summary":"Create Mutual Connections signal","description":"Find the mutual connections between two LinkedIn profiles - the people connected to both. Name any two people: a decision maker you want to meet and someone on your side, two executives of the same account, an investor and a founder. Each person connected to both is delivered, filtered to the roles and companies you target. Two parts, which you can use together or apart: a **one-time extract** of the mutual connections in the two existing networks, then, if you want, the **new** mutual connections every day.\n\n**Input:** `linkedinProfileUrls` (exactly two LinkedIn profile URLs, A and B, required); `oneTimeExtractCount` (how many mutual connections to deliver once, 0-25,000, defaults to 100; not metered by `dailyLeadLimit`); `dailyNewConnections` (true to keep delivering new mutual connections afterwards, up to `dailyLeadLimit` a day; defaults to false). Existing mutual connections are delivered only by the one-time extract, up to `oneTimeExtractCount`: with `0`, none is delivered or billed; optional persona targeting (`targetPersonas`, `customPersonaTitles`); optional ICP filters (`companySizeFilters`, `locations`, `industryFilters`, `excludedLocations`, `excludedCompanySizeFilters`, `excludedIndustryFilters`, `excludedTitles`, `excludedCompanyUrls`); optional enrichment toggles (`getEmails`, `getPhones`, `getSireneData`, `detectTechnologies`, `getHomepageContent`); `webhookUrl`, `dailyLeadLimit`, `duplicateHandling`, `status`. Activating with `status: active` checks that the two profiles are set and that your balance covers the one-time extract (`oneTimeExtractCount` x the price per lead), and answers 402 with the estimate when it does not. A profile that hides its connection list on LinkedIn cannot be read. How many mutual connections exist is only final once both networks have been read: follow it with `GET /api/v1/signals/{signalId}/mutual-connections`. Each mutual connection is billed as it is delivered.\n\n**Output:** each mutual connection is pushed to your `webhookUrl` as an enriched person lead: the contact (name, email if enriched, phone if enriched, title, location, LinkedIn profile URL, matched persona), their employer (company name, website, LinkedIn URL), and `signal.profile_a` / `signal.profile_b` - the two profiles they are connected to. `signal.tracked_company` is always empty.\n\n**Use cases:**\n- Warm introductions - compare a decision maker you want to meet with someone on your side (a salesperson, a founder, an investor) and reach the people who know both, so the first touch is a referral instead of a cold message.\n- Account mapping - compare two executives of the same account to find the people close to both, the ones who carry influence inside the buying group.\n- Ecosystem plays - compare the leader of a company you work with and the leader of a target account to find who sits at the crossroads of the two networks.","operationId":"create_mutual_connections_signal_api_v1_signals_mutual_connections_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/MutualConnectionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day for the daily part (`dailyNewConnections`). The one-time extract is bounded by `oneTimeExtractCount` instead.","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow'.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, the config must name exactly two different profiles (otherwise 400) and the balance must cover the one-time extract (`oneTimeExtractCount` x the price per lead), otherwise 402."}},"type":"object","required":["name","config"],"title":"MutualConnectionsCreate","description":"Create a Mutual Connections signal.","examples":[{"config":{"dailyNewConnections":true,"getEmails":true,"linkedinProfileUrls":["https://www.linkedin.com/in/claire-martin-cfo/","https://www.linkedin.com/in/thomas-bernard-ceo/"],"locations":["France"],"oneTimeExtractCount":100,"targetPersonas":["Sales Director","Marketing Director"]},"dailyLeadLimit":10,"name":"Mutual connections of Claire and Thomas","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Mutual connections of Claire and Thomas","value":{"name":"Mutual connections of Claire and Thomas","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":10,"status":"active","config":{"linkedinProfileUrls":["https://www.linkedin.com/in/claire-martin-cfo/","https://www.linkedin.com/in/thomas-bernard-ceo/"],"oneTimeExtractCount":100,"dailyNewConnections":true,"getEmails":true,"targetPersonas":["Sales Director","Marketing Director"],"locations":["France"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Mutual connections of Claire and Thomas","status":"active","signalTypeId":"mutual_connections","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"linkedinProfileUrls":["https://www.linkedin.com/in/claire-martin-cfo/","https://www.linkedin.com/in/thomas-bernard-ceo/"],"oneTimeExtractCount":100,"dailyNewConnections":true,"getEmails":true,"targetPersonas":["Sales Director","Marketing Director"],"locations":["France"]},"dailyLeadLimit":10,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config (The two LinkedIn profiles to compare), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (The two LinkedIn profiles to compare)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["linkedin_profile_urls"],"missing_field_labels":["The two LinkedIn profiles to compare"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_mutual_connections","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Always empty for this signal.","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"One of the two compared profiles (the one whose network the lead was read from).","default":""},"profile_a":{"type":"string","title":"Profile A","description":"LinkedIn profile URL of profile A.","default":""},"profile_b":{"type":"string","title":"Profile B","description":"LinkedIn profile URL of profile B.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookMutualConnectionsSignal","description":"Signal info for the mutual_connections signal.\n\nThe lead is connected to BOTH profiles you compared: ``profile_a`` and\n``profile_b`` (your two ``linkedinProfileUrls``, in order)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookMutualConnectionsPayload","description":"Webhook payload for the mutual_connections signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f","last_signal":"Mutual Connections","last_signal_date":"2026-05-31","name":"Mutual connections of Claire and Thomas","profile_a":"https://www.linkedin.com/in/claire-martin-cfo/","profile_b":"https://www.linkedin.com/in/thomas-bernard-ceo/","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/claire-martin-cfo/","type":"mutual_connections"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Always empty for this signal.","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"One of the two compared profiles (the one whose network the lead was read from).","default":""},"profile_a":{"type":"string","title":"Profile A","description":"LinkedIn profile URL of profile A.","default":""},"profile_b":{"type":"string","title":"Profile B","description":"LinkedIn profile URL of profile B.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookMutualConnectionsSignal","description":"Signal info for the mutual_connections signal.\n\nThe lead is connected to BOTH profiles you compared: ``profile_a`` and\n``profile_b`` (your two ``linkedinProfileUrls``, in order)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookMutualConnectionsPayload","description":"Webhook payload for the mutual_connections signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f","last_signal":"Mutual Connections","last_signal_date":"2026-05-31","name":"Mutual connections of Claire and Thomas","profile_a":"https://www.linkedin.com/in/claire-martin-cfo/","profile_b":"https://www.linkedin.com/in/thomas-bernard-ceo/","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/claire-martin-cfo/","type":"mutual_connections"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/new-decision-maker-watchlist":{"post":{"tags":["Signals"],"summary":"Create New Decision Maker Watchlist signal","description":"Get told when a new decision maker takes a role at one of your accounts - reach them while the seat is still being shaped, before the incumbent's supplier list has settled.\n\nWhere the Job Change watchlist follows PEOPLE you already know and tells you when they move, this one follows your COMPANIES and tells you who arrived. The person is the discovery: you do not need to have heard of them for the signal to find them.\n\n**Input:** `companies` (a name, a domain, or a LinkedIn company URL per entry - send the LinkedIn URL whenever you have it, it is the only one of the three that separates two companies sharing a name - or an object `{name, domain, linkedinUrl}` carrying all three; strings and objects can be mixed), `targetPersonas` (which roles count as a decision maker) and optional `customJobTitles` for titles your industry uses that the standard personas do not cover, `cadenceHours` (default 24), `dailyLeadLimit` (default 25), plus enrichment flags (`getEmails`, `getPhones`).\n\n**Output:** each person arriving into a matching role at a watched company is pushed to your `webhookUrl` as an enriched person-lead: a `signal` object, a `contact` object (name, new title, LinkedIn URL, matched persona, and email/phone when enrichment is on) and a `company` object for the account they joined. The first check returns everyone who has recently arrived; each check after that returns only what is new since the last, so an arrival is delivered once.\n\nAt least one of `targetPersonas` or `customJobTitles` is required - without a role filter the signal would return every job change at every watched company, which is the volume mode this signal exists to replace.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove companies with `POST` / `DELETE` on the same path.\n\n**Use cases:**\n- Land before the incumbent does - a new decision maker has no supplier loyalty yet and is actively rebuilding their stack; the first weeks are the widest the window ever gets.\n- Re-open a lost account - the person who chose against you has left, so the objection left with them; the arrival resets the evaluation.\n- Warm your own customer base - when a new leader takes over an account you already serve, reach them before they inherit an opinion of you from someone else.\n- Route to the right rep on arrival - push the arrival into your CRM against the account it belongs to, so ownership and sequencing happen the day it lands.","operationId":"create_new_decision_maker_watchlist_signal_api_v1_signals_new_decision_maker_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/NewDecisionMakerWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"NewDecisionMakerWatchlistCreate","examples":[{"config":{"cadenceHours":24,"companies":["https://www.linkedin.com/company/doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"Lemlist"],"customJobTitles":["Head of Revenue Operations"],"dailyLeadLimit":25,"getEmails":true,"targetPersonas":["Sales Director","CTO"]},"name":"Comptes strategiques - arrivees","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Comptes strategiques - arrivees","value":{"name":"Comptes strategiques - arrivees","webhookUrl":"https://example.com/webhooks/rodz","status":"active","config":{"companies":["https://www.linkedin.com/company/doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"Lemlist"],"targetPersonas":["Sales Director","CTO"],"customJobTitles":["Head of Revenue Operations"],"cadenceHours":24,"dailyLeadLimit":25,"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Comptes strategiques - arrivees","status":"active","signalTypeId":"new_decision_maker_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"targetPersonas":["Sales Director","CTO"],"customJobTitles":["Head of Revenue Operations"],"cadenceHours":24,"dailyLeadLimit":25,"getEmails":true},"dailyLeadLimit":100,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent for each person arriving into a matching role at a watched company. `previous_title` / `previous_company` say where they came from.","operationId":"new_decision_maker_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"previous_title":{"type":"string","title":"Previous Title","description":"Job title held before the change","default":""},"previous_company":{"type":"string","title":"Previous Company","description":"Employer before the change","default":""},"previous_company_linkedin_url":{"type":"string","title":"Previous Company Linkedin Url","description":"LinkedIn company URL of the previous employer","default":""},"previous_job_started_on":{"type":"string","title":"Previous Job Started On","description":"When the previous role started, as published (e.g. \"2022-03\")","default":""},"previous_job_ended_on":{"type":"string","title":"Previous Job Ended On","description":"When the previous role ended, as published (e.g. \"2026-04\")","default":""},"new_title":{"type":"string","title":"New Title","description":"Job title held after the change","default":""},"new_company":{"type":"string","title":"New Company","description":"Employer after the change","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When the NEW role started, as the profile publishes it: \"MM/YYYY\" (e.g. \"05/2026\"), when the profile states it. This is the date to test a change against: `previous_job_ended_on` is a different date whenever there was a gap between the two jobs. `new_job_start_month` carries the same month as \"YYYY-MM\".","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Month the NEW role started, always \"YYYY-MM\" (e.g. \"2026-05\"). Same value as `new_job_started_on`, in a sortable format. \"\" when unknown.","default":""},"change_type":{"type":"string","title":"Change Type","description":"What changed: \"company\" (moved employer), \"title\" (new role at the same employer), or \"both\".","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookJobChangeWatchlistSignal","description":"Signal info for the job_change_watchlist signal.\n\nThis signal reports a move by someone YOU put on the list, so the useful\npart is the before/after pair: ``previous_*`` is where the person was when\nyou added them, and the ``contact`` / ``company`` blocks describe where they\nare now. ``tracked_company`` is inherited and always present for shape\nparity with the other person signals, but carries no value here — the\nwatched subject is the person, not a company."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookJobChangeWatchlistPayload","description":"Webhook payload for the job_change_watchlist signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"VP Marketing"},"signal":{"change_type":"company","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Job Change Watchlist","last_signal_date":"2026-05-31","name":"My champions","new_company":"Tech Corp","new_job_start_month":"2026-05","new_job_started_on":"05/2026","new_title":"VP Marketing","previous_company":"Payfit","previous_company_linkedin_url":"https://www.linkedin.com/company/payfit/","previous_job_ended_on":"2026-04","previous_job_started_on":"2022-03","previous_title":"Head of Growth","tracked_company":"","type":"job_change_watchlist"}}]},"example":{"signal":{"id":"c3d4e5f6-a7b8-9012-cdef-345678901234","name":"Comptes strategiques - arrivees","type":"new_decision_maker_watchlist","last_signal":"New Decision Maker Watchlist","last_signal_date":"2026-08-14","tracked_company":"Doctolib","previous_title":"Sales Director","previous_company":"Payfit","new_title":"VP Sales","new_company":"Doctolib","change_type":"company"},"contact":{"lead_id":"d4e5f6a7-b8c9-0123-def4-456789012345","created_at":"2026-08-14T08:20:00+00:00","first_name":"Jean","last_name":"Martin","email":"jean.martin@doctolib.fr","phone":"","title":"VP Sales","location":"Paris, France","country_code":"FR","city":"Paris","linkedin_profile_url":"https://www.linkedin.com/in/jean-martin","sales_navigator_profile_url":"","matched_persona":"Sales Director"},"company":{"name":"Doctolib","website":"https://doctolib.fr","linkedin_url":"https://www.linkedin.com/company/doctolib","industry":"Software Development","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""},"previous_title":{"type":"string","title":"Previous Title","description":"Job title held before the change","default":""},"previous_company":{"type":"string","title":"Previous Company","description":"Employer before the change","default":""},"previous_company_linkedin_url":{"type":"string","title":"Previous Company Linkedin Url","description":"LinkedIn company URL of the previous employer","default":""},"previous_job_started_on":{"type":"string","title":"Previous Job Started On","description":"When the previous role started, as published (e.g. \"2022-03\")","default":""},"previous_job_ended_on":{"type":"string","title":"Previous Job Ended On","description":"When the previous role ended, as published (e.g. \"2026-04\")","default":""},"new_title":{"type":"string","title":"New Title","description":"Job title held after the change","default":""},"new_company":{"type":"string","title":"New Company","description":"Employer after the change","default":""},"new_job_started_on":{"type":"string","title":"New Job Started On","description":"When the NEW role started, as the profile publishes it: \"MM/YYYY\" (e.g. \"05/2026\"), when the profile states it. This is the date to test a change against: `previous_job_ended_on` is a different date whenever there was a gap between the two jobs. `new_job_start_month` carries the same month as \"YYYY-MM\".","default":""},"new_job_start_month":{"type":"string","title":"New Job Start Month","description":"Month the NEW role started, always \"YYYY-MM\" (e.g. \"2026-05\"). Same value as `new_job_started_on`, in a sortable format. \"\" when unknown.","default":""},"change_type":{"type":"string","title":"Change Type","description":"What changed: \"company\" (moved employer), \"title\" (new role at the same employer), or \"both\".","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookJobChangeWatchlistSignal","description":"Signal info for the job_change_watchlist signal.\n\nThis signal reports a move by someone YOU put on the list, so the useful\npart is the before/after pair: ``previous_*`` is where the person was when\nyou added them, and the ``contact`` / ``company`` blocks describe where they\nare now. ``tracked_company`` is inherited and always present for shape\nparity with the other person signals, but carries no value here — the\nwatched subject is the person, not a company."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookJobChangeWatchlistPayload","description":"Webhook payload for the job_change_watchlist signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":"VP Marketing"},"signal":{"change_type":"company","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Job Change Watchlist","last_signal_date":"2026-05-31","name":"My champions","new_company":"Tech Corp","new_job_start_month":"2026-05","new_job_started_on":"05/2026","new_title":"VP Marketing","previous_company":"Payfit","previous_company_linkedin_url":"https://www.linkedin.com/company/payfit/","previous_job_ended_on":"2026-04","previous_job_started_on":"2022-03","previous_title":"Head of Growth","tracked_company":"","type":"job_change_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/person-connections":{"post":{"tags":["Signals"],"summary":"Create Person Connections signal","description":"Get the people in the LinkedIn networks of the people you name — your investors, advisors, customers, champions, or any industry figure — filtered to the roles and companies you sell to. Two parts, which you can use together or apart: a **one-time extract** of their existing connections, delivered as fast as they are read, then, if you want, the people who **newly connect** with them, every day.\n\n**Input:** `linkedinProfileUrls` (1-50 LinkedIn profile URLs of the people to watch, required); `oneTimeExtractCount` (how many people to deliver once from their existing connections, counted in leads delivered after your filters, across all watched people; 0-25,000, defaults to 500; when their networks hold fewer matching people, everyone who matches is delivered; not metered by `dailyLeadLimit`); `dailyNewConnections` (true to keep delivering new connections after the one-time extract, up to `dailyLeadLimit` a day: only people who connect with a watched person after the signal started watching them; defaults to false, which stops the signal once the one-time extract is complete). Existing connections are delivered only by the one-time extract, up to `oneTimeExtractCount`: with `0`, none is delivered or billed; optional persona targeting (`targetPersonas`, `customPersonaTitles`); optional ICP filters (`companySizeFilters`, `locations`, `industryFilters`, `excludedLocations`, `excludedCompanySizeFilters`, `excludedIndustryFilters`, `excludedTitles`, `excludedCompanyUrls`) — with no filter at all, everyone is delivered; optional enrichment toggles (`getEmails`, `getPhones`, `getSireneData`, `detectTechnologies`, `getHomepageContent`); `webhookUrl`, `dailyLeadLimit`, `duplicateHandling`, `status`. Each lead is billed as it is delivered: **3 credits per lead for the one-time extract, then 5 credits per lead for the daily new connections**. Activating with `status: active` checks that your balance covers the one-time extract (`oneTimeExtractCount` × 3 credits) and answers 402 with the estimate when it does not. A watched person who hides their connection list on LinkedIn cannot be read.\n\n**Output:** each matching person is pushed to your `webhookUrl` as an enriched person lead: the contact (name, email if enriched, phone if enriched, title, location, LinkedIn profile URL, matched persona), their employer (company name, website, LinkedIn URL, plus tech stack and homepage content when those enrichments are enabled), and `signal.tracked_contact` — the watched person whose network the lead belongs to, so a signal watching several people tells you which one produced each lead. `signal.tracked_company` is always empty. The single-signal responses report progress in `applied.oneTimeExtract` (`target`, `delivered`, `status`).\n\n**Use cases:**\n- Warm-network prospecting - reach the people around your investors, advisors, customers or champions, filtered to the roles and companies you sell to, instead of cold lists.\n- Account mapping from one contact - watch a key decision maker and get the colleagues and peers in their network who match your ICP.\n- Event and ecosystem follow-up - watch a speaker, a co-marketing ally or an industry figure and turn their audience of peers into a targeted list, then keep receiving the people who join it.","operationId":"create_person_connections_signal_api_v1_signals_person_connections_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/PersonConnectionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day for the daily part (`dailyNewConnections`). The one-time extract is bounded by `oneTimeExtractCount` instead.","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, the config is validated and the balance must cover the one-time extract (`oneTimeExtractCount` x the price per lead), otherwise 402."}},"type":"object","required":["name","config"],"title":"PersonConnectionsCreate","description":"Create a Person Connections signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500","501-1000"],"customPersonaTitles":["Head of Growth"],"dailyNewConnections":true,"excludedCompanyUrls":[],"excludedTitles":["Intern"],"getEmails":true,"getPhones":false,"industryFilters":["Software Development"],"linkedinProfileUrls":["https://www.linkedin.com/in/sophie-laurent-advisor/","https://www.linkedin.com/in/marc-dubois-investor/"],"locations":["France"],"oneTimeExtractCount":800,"targetPersonas":["Sales Director","Marketing Director"]},"dailyLeadLimit":20,"name":"Network of our advisory board","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"},{"config":{"dailyNewConnections":false,"linkedinProfileUrls":["https://www.linkedin.com/in/claire-martin-ceo/"],"oneTimeExtractCount":2500},"name":"Everyone in our CEO's network, once","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Network of our advisory board","value":{"name":"Network of our advisory board","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":20,"status":"active","config":{"linkedinProfileUrls":["https://www.linkedin.com/in/sophie-laurent-advisor/","https://www.linkedin.com/in/marc-dubois-investor/"],"oneTimeExtractCount":800,"dailyNewConnections":true,"getEmails":true,"getPhones":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Sales Director","Marketing Director"],"customPersonaTitles":["Head of Growth"],"locations":["France"],"industryFilters":["Software Development"],"excludedTitles":["Intern"],"excludedCompanyUrls":[]}}},"example2":{"summary":"Everyone in our CEO's network, once","value":{"name":"Everyone in our CEO's network, once","webhookUrl":"https://your-server.com/webhooks/rodz","status":"active","config":{"linkedinProfileUrls":["https://www.linkedin.com/in/claire-martin-ceo/"],"oneTimeExtractCount":2500,"dailyNewConnections":false}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Network of our advisory board","status":"active","signalTypeId":"person_connections","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"linkedinProfileUrls":["https://www.linkedin.com/in/sophie-laurent-advisor/","https://www.linkedin.com/in/marc-dubois-investor/"],"oneTimeExtractCount":800,"dailyNewConnections":true,"getEmails":true,"getPhones":false,"companySizeFilters":["51-200","201-500","501-1000"],"targetPersonas":["Sales Director","Marketing Director"],"customPersonaTitles":["Head of Growth"],"locations":["France"],"industryFilters":["Software Development"],"excludedTitles":["Intern"],"excludedCompanyUrls":[]},"dailyLeadLimit":20,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{"allowUnknownCompanySize":false},"warnings":[{"code":"UNKNOWN_SIZE_NOT_ACCEPTED","severity":"info","field":"allowUnknownCompanySize","message":"Companies whose size cannot be determined are accepted only when the size selection includes a band under 51 employees (\"Self-employed\", \"1-10\", \"11-50\"). This selection does not, so such companies are not delivered.","values":[]}]}}}},"400":{"description":"Invalid request: missing required config (People to Watch (LinkedIn profile URLs)), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (People to Watch (LinkedIn profile URLs))","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["linkedin_profile_urls"],"missing_field_labels":["People to Watch (LinkedIn profile URLs)"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"person_lead_webhook_person_connections","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Always empty for this signal.","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person (one of your ``linkedinProfileUrls``) whose connections include the lead.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPersonConnectionsSignal","description":"Signal info for the person_connections signal.\n\n``tracked_contact`` names the watched person whose network the lead belongs\nto, so a signal watching several people tells you which one produced each\nlead. ``tracked_company`` is always empty: this signal watches people, not\ncompanies."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookPersonConnectionsPayload","description":"Webhook payload for the person_connections signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"b7c8d9e0-f1a2-4b3c-8d4e-5f6a7b8c9d0e","last_signal":"Person Connections","last_signal_date":"2026-05-31","name":"Network of our advisory board","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/sophie-laurent-advisor/","type":"person_connections"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Always empty for this signal.","default":""},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the watched person (one of your ``linkedinProfileUrls``) whose connections include the lead.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPersonConnectionsSignal","description":"Signal info for the person_connections signal.\n\n``tracked_contact`` names the watched person whose network the lead belongs\nto, so a signal watching several people tells you which one produced each\nlead. ``tracked_company`` is always empty: this signal watches people, not\ncompanies."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookPersonConnectionsPayload","description":"Webhook payload for the person_connections signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"VP Sales","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"b7c8d9e0-f1a2-4b3c-8d4e-5f6a7b8c9d0e","last_signal":"Person Connections","last_signal_date":"2026-05-31","name":"Network of our advisory board","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/sophie-laurent-advisor/","type":"person_connections"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/public-contract-award":{"post":{"tags":["Signals"],"summary":"Create Public Contract Award signal","description":"Identify companies scaling after winning French public contracts — those with immediate budget and operational expansion needs. The winning vendor (*titulaire*) becomes your lead. **Input:** your webhook URL (`webhookUrl`), daily lead cap (`dailyLeadLimit`), and filters on the winning company: contract keywords/exclusions (`keywords`, `keywordsExclude`), procurement classification (`cpvCodes`), contract value range (`minContractValue`, `maxContractValue`), company size (`titulaireCategories`: PME/ETI/GE), and geography for both winner (`titulaireRegions`, `titulaireDepartements`) and buyer (`acheteurRegions`, `acheteurDepartements`). Optionally enable enrichment (`getEmails`, `getPhones`, `getSireneData`) and person-level targeting via `targetPersonas` (role titles like \"CEO\", \"CFO\"). **Output:** an immediate HTTP 201 response with your signal ID and configuration. Matching leads are then delivered to your `webhookUrl` as they are detected — each payload includes the contract details, the winning company, and any matched decision-makers — filtered by your geography and size configuration and capped at your daily limit. Duplicate awards are not re-sent.\n\n**Use cases:**\n- Winner outreach — companies that just won a public contract have new budget and delivery needs; pitch enabling services.\n- Subcontracting — offer to subcontract on the awarded work.","operationId":"create_public_contract_award_signal_api_v1_signals_public_contract_award_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/PublicContractAwardConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"PublicContractAwardCreate","description":"Create a Public Contract Award signal.\n\nSurfaces French SMEs and mid-market companies that have just won a public\ncontract — strong intent for B2B vendors selling supporting services\n(accounting, legal, recruiting, payroll, project management, SaaS, etc.)\nto companies that are scaling. Source: DECP open data feed; the *titulaire*\n(winning vendor) is the lead. Returns company-level leads by default;\nenable persona targeting to add person leads at the winning company.","examples":[{"config":{"acheteurDepartements":[],"acheteurRegions":[],"cpvCodes":[],"customPersonaTitles":[],"detectTechnologies":false,"excludedTitles":[],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":true,"keywords":[],"keywordsExclude":[],"minContractValue":50000,"targetPersonas":["CEO","CFO","Operations Director"],"titulaireCategories":["PME","ETI"],"titulaireDepartements":[],"titulaireRegions":[]},"dailyLeadLimit":50,"name":"B2B services prospecting — French SMEs winning €50k+ contracts","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"},{"config":{"acheteurRegions":["Île-de-France"],"cpvCodes":["72000000","48000000"],"getEmails":true,"getSireneData":true,"keywords":["santé","hôpital"],"minContractValue":100000,"targetPersonas":["CTO","IT Director"],"titulaireCategories":["PME","ETI","GE"]},"dailyLeadLimit":50,"name":"IT vendors targeting healthcare contract winners","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"B2B services prospecting — French SMEs winning €50k+ contracts","value":{"name":"B2B services prospecting — French SMEs winning €50k+ contracts","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"keywords":[],"keywordsExclude":[],"cpvCodes":[],"minContractValue":50000,"titulaireCategories":["PME","ETI"],"titulaireRegions":[],"titulaireDepartements":[],"acheteurRegions":[],"acheteurDepartements":[],"getEmails":true,"getPhones":false,"getSireneData":true,"detectTechnologies":false,"getHomepageContent":false,"targetPersonas":["CEO","CFO","Operations Director"],"customPersonaTitles":[],"excludedTitles":[]}}},"example2":{"summary":"IT vendors targeting healthcare contract winners","value":{"name":"IT vendors targeting healthcare contract winners","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"keywords":["santé","hôpital"],"cpvCodes":["72000000","48000000"],"minContractValue":100000,"titulaireCategories":["PME","ETI","GE"],"acheteurRegions":["Île-de-France"],"getEmails":true,"getSireneData":true,"targetPersonas":["CTO","IT Director"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"B2B services prospecting — French SMEs winning €50k+ contracts","status":"active","signalTypeId":"public_contract_award","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"keywords":[],"keywordsExclude":[],"cpvCodes":[],"minContractValue":50000,"titulaireCategories":["PME","ETI"],"titulaireRegions":[],"titulaireDepartements":[],"acheteurRegions":[],"acheteurDepartements":[],"getEmails":true,"getPhones":false,"getSireneData":true,"detectTechnologies":false,"getHomepageContent":false,"targetPersonas":["CEO","CFO","Operations Director"],"customPersonaTitles":[],"excludedTitles":[]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching job is found. `contact` is null unless persona targeting is enabled.","operationId":"job_lead_webhook_public_contract_award","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"contract_subject":{"type":"string","title":"Contract Subject","description":"Subject of the awarded contract","default":""},"contract_value":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Contract Value","description":"Awarded amount; \"\" when the award does not publish one","default":""},"contract_currency":{"type":"string","title":"Contract Currency","description":"Currency of contract_value — always \"EUR\" when a value is present","default":""},"contract_cpv":{"type":"string","title":"Contract Cpv","description":"CPV classification code of the contract","default":""},"contract_duration_months":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Contract Duration Months","description":"Contract duration in months; \"\" when absent","default":""},"bids_received":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Bids Received","description":"Number of bids received for the contract; \"\" when absent","default":""},"procedure_type":{"type":"string","title":"Procedure Type","description":"Award procedure as published (e.g. \"Procédure adaptée\")","default":""},"buyer_name":{"type":"string","title":"Buyer Name","description":"Name of the public buyer that awarded the contract","default":""},"buyer_siret":{"type":"string","title":"Buyer Siret","description":"SIRET of the public buyer","default":""},"award_date":{"type":"string","title":"Award Date","description":"Date the contract was awarded (YYYY-MM-DD)","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPublicContractAwardSignal","description":"Signal info for an awarded public contract.\n\nThe lead is the WINNING vendor, so the company block describes the awardee\nand these fields describe the contract they won and who awarded it. The\ncontract title is also carried in ``job_offer_title`` — frozen, as above."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookPublicContractAwardPayload","description":"Webhook payload for the public_contract_award signal. The contract title is\ncarried in job_offer_title; the lead is the winning vendor (titulaire).","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"","created_at":"2026-05-31T14:30:00+00:00","email":"","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"","location":"","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":""},"signal":{"award_date":"2026-05-22","bids_received":6,"buyer_name":"Commune de Saint-Herblain","buyer_siret":"21440162000015","contract_cpv":"90910000","contract_currency":"EUR","contract_duration_months":48,"contract_subject":"Nettoyage courant des batiments communaux (lot 1)","contract_value":248000.0,"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-22","job_offer_description":"","job_offer_location":"","job_offer_published_date":"2026-05-22","job_offer_source":"DECP","job_offer_title":"Nettoyage courant des batiments communaux (lot 1)","job_offer_url":"","last_signal":"Public Contract Award","last_signal_date":"2026-05-31","matched_keywords":"nettoyage","name":"Cleaning contract winners","procedure_type":"Procedure adaptee","type":"public_contract_award"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"contract_subject":{"type":"string","title":"Contract Subject","description":"Subject of the awarded contract","default":""},"contract_value":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Contract Value","description":"Awarded amount; \"\" when the award does not publish one","default":""},"contract_currency":{"type":"string","title":"Contract Currency","description":"Currency of contract_value — always \"EUR\" when a value is present","default":""},"contract_cpv":{"type":"string","title":"Contract Cpv","description":"CPV classification code of the contract","default":""},"contract_duration_months":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Contract Duration Months","description":"Contract duration in months; \"\" when absent","default":""},"bids_received":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Bids Received","description":"Number of bids received for the contract; \"\" when absent","default":""},"procedure_type":{"type":"string","title":"Procedure Type","description":"Award procedure as published (e.g. \"Procédure adaptée\")","default":""},"buyer_name":{"type":"string","title":"Buyer Name","description":"Name of the public buyer that awarded the contract","default":""},"buyer_siret":{"type":"string","title":"Buyer Siret","description":"SIRET of the public buyer","default":""},"award_date":{"type":"string","title":"Award Date","description":"Date the contract was awarded (YYYY-MM-DD)","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPublicContractAwardSignal","description":"Signal info for an awarded public contract.\n\nThe lead is the WINNING vendor, so the company block describes the awardee\nand these fields describe the contract they won and who awarded it. The\ncontract title is also carried in ``job_offer_title`` — frozen, as above."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookPublicContractAwardPayload","description":"Webhook payload for the public_contract_award signal. The contract title is\ncarried in job_offer_title; the lead is the winning vendor (titulaire).","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"","created_at":"2026-05-31T14:30:00+00:00","email":"","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"","location":"","matched_persona":"","phone":"","sales_navigator_profile_url":"","title":""},"signal":{"award_date":"2026-05-22","bids_received":6,"buyer_name":"Commune de Saint-Herblain","buyer_siret":"21440162000015","contract_cpv":"90910000","contract_currency":"EUR","contract_duration_months":48,"contract_subject":"Nettoyage courant des batiments communaux (lot 1)","contract_value":248000.0,"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-22","job_offer_description":"","job_offer_location":"","job_offer_published_date":"2026-05-22","job_offer_source":"DECP","job_offer_title":"Nettoyage courant des batiments communaux (lot 1)","job_offer_url":"","last_signal":"Public Contract Award","last_signal_date":"2026-05-31","matched_keywords":"nettoyage","name":"Cleaning contract winners","procedure_type":"Procedure adaptee","type":"public_contract_award"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/public-tenders":{"post":{"tags":["Signals"],"summary":"Create Public Tenders signal","description":"Find organizations actively buying — discover procurement opportunities the moment they publish tenders. Monitor French public tenders (BOAMP) and/or European tenders (TED) matching your keywords and filters, and push each matched tender to your webhook as a lead for the buying organization.\n\n**Input:** signal name (`name`), webhook URL (`webhookUrl`), optional keyword filters (`keywords`, `keywordsExclude`), tender sources (`sources`: \"boamp\" and/or \"ted\"), notice types (`noticeTypes` for BOAMP: \"APPEL_OFFRE\", \"MAPA\", \"AVIS_DE_CONCESSION\"), market types (`marketTypes`: \"Services\", \"Fournitures\", \"Travaux\"), French department codes (`departmentCodes`), TED country codes (`countryCodes`), CPV service codes (`cpvCodes`), response deadline filters (`minDaysUntilDeadline`), and optional persona targeting (`enablePersonaTargeting`, `targetPersonas`) to identify decision-makers. Enrichment options (`getEmails`, `getPhones`, `detectTechnologies`) use credits.\n\n**Output:** each matching tender is pushed to your `webhookUrl` as a lead containing the buyer organization's name, location, tender title/URL/deadline, and market type. If persona targeting is enabled, matched decision-makers at the buying organization are included as the contact; otherwise contact is omitted. Each tender is delivered once, subject to your daily limit.\n\n**Use cases:**\n- Bid-opportunity alerts — get notified of relevant public tenders to bid on.\n- Partner sourcing — find companies bidding, to partner or subcontract with.","operationId":"create_public_tenders_signal_api_v1_signals_public_tenders_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/PublicTendersConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"PublicTendersCreate","description":"Create a Public Tenders signal (BOAMP and/or TED).","examples":[{"config":{"categoryDescriptors":[],"departmentCodes":["75"],"detectTechnologies":false,"familleFilter":["Avis de marché","MAPA"],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"keywords":["informatique","logiciel"],"keywordsExclude":[],"marketTypes":["Services"],"sources":["boamp"]},"dailyLeadLimit":50,"name":"IT services tenders in Paris","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"},{"config":{"countryCodes":["FR","DE","IT"],"cpvCodes":["72000000"],"keywords":["software","IT services"],"sources":["ted"],"tedNoticeTypes":["cn-standard"]},"dailyLeadLimit":50,"name":"European IT tenders","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"IT services tenders in Paris","value":{"name":"IT services tenders in Paris","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"sources":["boamp"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"keywords":["informatique","logiciel"],"keywordsExclude":[],"departmentCodes":["75"],"marketTypes":["Services"],"categoryDescriptors":[],"familleFilter":["Avis de marché","MAPA"]}}},"example2":{"summary":"European IT tenders","value":{"name":"European IT tenders","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"sources":["ted"],"keywords":["software","IT services"],"countryCodes":["FR","DE","IT"],"cpvCodes":["72000000"],"tedNoticeTypes":["cn-standard"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"IT services tenders in Paris","status":"active","signalTypeId":"public_tenders","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"sources":["boamp"],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"keywords":["informatique","logiciel"],"keywordsExclude":[],"departmentCodes":["75"],"marketTypes":["Services"],"categoryDescriptors":[],"familleFilter":["Avis de marché","MAPA"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching job is found. `contact` is null unless persona targeting is enabled.","operationId":"job_lead_webhook_public_tenders","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"tender_description":{"type":"string","title":"Tender Description","description":"Full description of the tender as published","default":""},"tender_deadline":{"type":"string","title":"Tender Deadline","description":"Deadline for submitting a response (ISO-8601); \"\" when the notice sets none","default":""},"tender_published_date":{"type":"string","title":"Tender Published Date","description":"Publication date (ISO-8601)","default":""},"tender_cpv_code":{"type":"string","title":"Tender Cpv Code","description":"Primary CPV classification code (e.g. \"55000000\")","default":""},"tender_market_type":{"type":"string","title":"Tender Market Type","description":"Market type as published (e.g. \"services\", \"travaux\")","default":""},"tender_nature":{"type":"string","title":"Tender Nature","description":"Notice nature as published by the source","default":""},"tender_submission_url":{"type":"string","title":"Tender Submission Url","description":"Direct URL to the submission platform, when the notice carries one","default":""},"tender_source":{"type":"string","title":"Tender Source","description":"Publication source: \"boamp\" (French) or \"ted\" (European)","default":""},"buyer_siren":{"type":"string","title":"Buyer Siren","description":"SIREN of the contracting authority (French notices)","default":""},"buyer_city":{"type":"string","title":"Buyer City","description":"City of the contracting authority","default":""},"buyer_website":{"type":"string","title":"Buyer Website","description":"Website of the contracting authority","default":""},"buyer_contact_email":{"type":"string","title":"Buyer Contact Email","description":"Contact email published on the notice for this procurement","default":""},"buyer_contact_phone":{"type":"string","title":"Buyer Contact Phone","description":"Contact phone published on the notice for this procurement","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPublicTendersSignal","description":"Signal info for a published tender notice.\n\nExtends the job-offer block rather than replacing it: the notice's title and\nURL have always travelled in ``job_offer_title`` / ``job_offer_url`` and live\nconsumers parse them there, so those keys are frozen. Everything that makes a\nnotice actionable — the response deadline, the full description, the buyer's\nown contact details — is added alongside."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookPublicTendersPayload","description":"Webhook payload for the public_tenders signal. The tender title/URL are\ncarried in the job_offer_title / job_offer_url fields.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"commandepublique@example.com","first_name":"Jean-Francois","last_name":"Auby","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"33","matched_persona":"","phone":"+33 5 57 34 53 20","sales_navigator_profile_url":"","title":""},"signal":{"buyer_city":"Bordeaux","buyer_contact_email":"commandepublique@example.com","buyer_contact_phone":"+33 5 57 34 53 20","buyer_siren":"213300631","buyer_website":"https://www.bordeaux-metropole.fr","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-25","job_offer_description":"","job_offer_location":"33","job_offer_published_date":"2026-05-25","job_offer_source":"BOAMP","job_offer_title":"Maitrise d'oeuvre - rehabilitation et extension du siege","job_offer_url":"https://www.boamp.fr/avis/detail/26-63010","last_signal":"Public Tender","last_signal_date":"2026-05-31","matched_keywords":"maitrise d'oeuvre","name":"BOAMP tenders - facilities","tender_cpv_code":"71200000","tender_deadline":"2026-06-30T16:00:00+00:00","tender_description":"Mission de maitrise d'oeuvre pour la rehabilitation et l'extension du siege administratif, tous corps d'etat.","tender_market_type":"services","tender_nature":"cn-standard","tender_published_date":"2026-05-25T02:00:00+00:00","tender_source":"boamp","tender_submission_url":"https://www.marches-securises.fr/entreprise/?module=dossier&idDossier=1234567","type":"public_tenders"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"tender_description":{"type":"string","title":"Tender Description","description":"Full description of the tender as published","default":""},"tender_deadline":{"type":"string","title":"Tender Deadline","description":"Deadline for submitting a response (ISO-8601); \"\" when the notice sets none","default":""},"tender_published_date":{"type":"string","title":"Tender Published Date","description":"Publication date (ISO-8601)","default":""},"tender_cpv_code":{"type":"string","title":"Tender Cpv Code","description":"Primary CPV classification code (e.g. \"55000000\")","default":""},"tender_market_type":{"type":"string","title":"Tender Market Type","description":"Market type as published (e.g. \"services\", \"travaux\")","default":""},"tender_nature":{"type":"string","title":"Tender Nature","description":"Notice nature as published by the source","default":""},"tender_submission_url":{"type":"string","title":"Tender Submission Url","description":"Direct URL to the submission platform, when the notice carries one","default":""},"tender_source":{"type":"string","title":"Tender Source","description":"Publication source: \"boamp\" (French) or \"ted\" (European)","default":""},"buyer_siren":{"type":"string","title":"Buyer Siren","description":"SIREN of the contracting authority (French notices)","default":""},"buyer_city":{"type":"string","title":"Buyer City","description":"City of the contracting authority","default":""},"buyer_website":{"type":"string","title":"Buyer Website","description":"Website of the contracting authority","default":""},"buyer_contact_email":{"type":"string","title":"Buyer Contact Email","description":"Contact email published on the notice for this procurement","default":""},"buyer_contact_phone":{"type":"string","title":"Buyer Contact Phone","description":"Contact phone published on the notice for this procurement","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPublicTendersSignal","description":"Signal info for a published tender notice.\n\nExtends the job-offer block rather than replacing it: the notice's title and\nURL have always travelled in ``job_offer_title`` / ``job_offer_url`` and live\nconsumers parse them there, so those keys are frozen. Everything that makes a\nnotice actionable — the response deadline, the full description, the buyer's\nown contact details — is added alongside."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookPublicTendersPayload","description":"Webhook payload for the public_tenders signal. The tender title/URL are\ncarried in the job_offer_title / job_offer_url fields.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"commandepublique@example.com","first_name":"Jean-Francois","last_name":"Auby","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"33","matched_persona":"","phone":"+33 5 57 34 53 20","sales_navigator_profile_url":"","title":""},"signal":{"buyer_city":"Bordeaux","buyer_contact_email":"commandepublique@example.com","buyer_contact_phone":"+33 5 57 34 53 20","buyer_siren":"213300631","buyer_website":"https://www.bordeaux-metropole.fr","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-25","job_offer_description":"","job_offer_location":"33","job_offer_published_date":"2026-05-25","job_offer_source":"BOAMP","job_offer_title":"Maitrise d'oeuvre - rehabilitation et extension du siege","job_offer_url":"https://www.boamp.fr/avis/detail/26-63010","last_signal":"Public Tender","last_signal_date":"2026-05-31","matched_keywords":"maitrise d'oeuvre","name":"BOAMP tenders - facilities","tender_cpv_code":"71200000","tender_deadline":"2026-06-30T16:00:00+00:00","tender_description":"Mission de maitrise d'oeuvre pour la rehabilitation et l'extension du siege administratif, tous corps d'etat.","tender_market_type":"services","tender_nature":"cn-standard","tender_published_date":"2026-05-25T02:00:00+00:00","tender_source":"boamp","tender_submission_url":"https://www.marches-securises.fr/entreprise/?module=dossier&idDossier=1234567","type":"public_tenders"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/public-tenders-watchlist":{"post":{"tags":["Signals"],"summary":"Create Public Tenders Watchlist signal","description":"Watch a fixed list of public buyers and get told when one of them publishes a tender — a moment when the budget is already approved and the buyer is obliged to consider whoever answers.\n\nWhere the Public Tenders signal DISCOVERS notices from keywords and geography, this one starts from your list: the public bodies you already sell to, or the accounts you are trying to win.\n\n**Input:** `companies` (the buyers to watch, by name), `keywords` and `keywordsExclude` applied to the notice subject, `sources` (`boamp` for France, `ted` for Europe), `noticeTypes`, `marketTypes`, and `minDaysUntilDeadline` to drop notices closing too soon to answer, plus optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `maxLeadsPerCompany`).\n\n**Output:** one company-level lead per matching notice, the buyer being the company. The notice title, URL and deadline travel on the `signal` block. A notice is delivered ONCE.\n\n**Persona targeting changes WHAT you receive; it does not add to it.** Left off, a notice delivers the company-level lead described above. Turned on, that lead is REPLACED by one lead per matching person at the buying organisation — so one notice can deliver several payloads, or none at all if nobody matches. `maxLeadsPerCompany` caps how many; `personaExportMode` chooses between the best-ranked contacts (the default) and every match. Persona leads are billed per person found, not per notice. On this signal in particular, reaching the people first means resolving the buyer's LinkedIn company page from an administrative name — the same hard match described below — so expect it to succeed less often here than on private companies.\n\n**How buyers are matched, and the honest limit.** A notice names its buyer only by an administrative name, so matching uses two exact keys: an official company identifier where one could be resolved, and the name otherwise. Never a fuzzy search — looking a name like \"Ville de Limoges\" up in a company register confidently returns unrelated private companies with similar names, and billing you for an organisation you never listed is worse than missing one. In practice an identifier is available for a minority of French buyers and for none of the European ones, so give buyer names exactly as they appear on the notices when you can.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response. Read what is actually watched with `GET /api/v1/watchlists/{signalId}/companies`, and add or remove buyers with `POST` / `DELETE` on the same path.","operationId":"create_public_tenders_watchlist_signal_api_v1_signals_public_tenders_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/PublicTendersWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"PublicTendersWatchlistCreate","examples":[{"config":{"companies":["Toulouse Metropole",{"domain":"chu-bordeaux.fr","name":"CHU de Bordeaux"},"Ville de Quimper"],"getEmails":true,"keywords":["logiciel","CRM"],"minDaysUntilDeadline":7,"sources":["boamp","ted"]},"dailyLeadLimit":25,"name":"Tenders from my accounts","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Tenders from my accounts","value":{"name":"Tenders from my accounts","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companies":["Toulouse Metropole",{"name":"CHU de Bordeaux","domain":"chu-bordeaux.fr"},"Ville de Quimper"],"keywords":["logiciel","CRM"],"sources":["boamp","ted"],"minDaysUntilDeadline":7,"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Tenders from my accounts","status":"active","signalTypeId":"public_tenders_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"keywords":["logiciel","CRM"],"sources":["boamp","ted"],"minDaysUntilDeadline":7,"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per notice published by a watched buyer and matching your keywords.","operationId":"public_tenders_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"tender_description":{"type":"string","title":"Tender Description","description":"Full description of the tender as published","default":""},"tender_deadline":{"type":"string","title":"Tender Deadline","description":"Deadline for submitting a response (ISO-8601); \"\" when the notice sets none","default":""},"tender_published_date":{"type":"string","title":"Tender Published Date","description":"Publication date (ISO-8601)","default":""},"tender_cpv_code":{"type":"string","title":"Tender Cpv Code","description":"Primary CPV classification code (e.g. \"55000000\")","default":""},"tender_market_type":{"type":"string","title":"Tender Market Type","description":"Market type as published (e.g. \"services\", \"travaux\")","default":""},"tender_nature":{"type":"string","title":"Tender Nature","description":"Notice nature as published by the source","default":""},"tender_submission_url":{"type":"string","title":"Tender Submission Url","description":"Direct URL to the submission platform, when the notice carries one","default":""},"tender_source":{"type":"string","title":"Tender Source","description":"Publication source: \"boamp\" (French) or \"ted\" (European)","default":""},"buyer_siren":{"type":"string","title":"Buyer Siren","description":"SIREN of the contracting authority (French notices)","default":""},"buyer_city":{"type":"string","title":"Buyer City","description":"City of the contracting authority","default":""},"buyer_website":{"type":"string","title":"Buyer Website","description":"Website of the contracting authority","default":""},"buyer_contact_email":{"type":"string","title":"Buyer Contact Email","description":"Contact email published on the notice for this procurement","default":""},"buyer_contact_phone":{"type":"string","title":"Buyer Contact Phone","description":"Contact phone published on the notice for this procurement","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPublicTendersWatchlistSignal","description":"Signal info for a tender at a WATCHED buyer.\n\nIdentical to the open Public Tenders block. Declared separately for the same\nreason its payload is: a shared ``$ref`` would name both signals' type after\nwhichever was declared first."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookPublicTendersWatchlistPayload","description":"Webhook payload for public_tenders_watchlist.\n\nSame shape as the open Public Tenders signal — one company-level lead per\nmatching notice, the buyer being the company — but declared as its own model\nrather than reusing that one. A shared ``$ref`` makes a generated client name\nBOTH signals' payload after whichever declared it first, so integrators of\nthis signal would find their type named after a signal they never\nsubscribed to.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marchespublics@example.fr","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"29","matched_persona":"","phone":"+33 2 98 98 89 89","sales_navigator_profile_url":"","title":""},"signal":{"buyer_city":"Quimper","buyer_contact_email":"marches@example.com","buyer_contact_phone":"","buyer_siren":"212900195","buyer_website":"https://www.quimper.bzh","id":"f6a7b8c9-d0e1-4f2a-b3c4-d5e6f7a8b9c0","job_offer_date":"2026-08-16","job_offer_description":"","job_offer_location":"29","job_offer_published_date":"2026-08-16","job_offer_source":"BOAMP","job_offer_title":"Fourniture et livraison de materiel scenique","job_offer_url":"https://www.boamp.fr/avis/detail/26-80902","last_signal":"Public Tenders Watchlist","last_signal_date":"2026-08-17","matched_keywords":"materiel scenique","name":"Tenders from my accounts","tender_cpv_code":"31500000","tender_deadline":"2026-09-15T12:00:00+00:00","tender_description":"Fourniture et livraison de materiel scenique pour l'equipement du centre culturel municipal.","tender_market_type":"fournitures","tender_nature":"cn-standard","tender_published_date":"2026-08-16T02:00:00+00:00","tender_source":"boamp","tender_submission_url":"","type":"public_tenders_watchlist"}}]},"example":{"signal":{"id":"f6a7b8c9-d0e1-4f2a-b3c4-d5e6f7a8b9c0","name":"Tenders from my accounts","type":"public_tenders_watchlist","last_signal":"Public Tenders Watchlist","last_signal_date":"2026-08-17","job_offer_url":"https://www.boamp.fr/avis/detail/26-80902","job_offer_title":"Fourniture et livraison de materiel scenique","job_offer_location":"29","job_offer_source":"BOAMP","matched_keywords":"materiel scenique"},"contact":{},"company":{"name":"Ville de Quimper","website":"","linkedin_url":"","industry":"","location":"29","hq_country_code":"","hq_city":""}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"tender_description":{"type":"string","title":"Tender Description","description":"Full description of the tender as published","default":""},"tender_deadline":{"type":"string","title":"Tender Deadline","description":"Deadline for submitting a response (ISO-8601); \"\" when the notice sets none","default":""},"tender_published_date":{"type":"string","title":"Tender Published Date","description":"Publication date (ISO-8601)","default":""},"tender_cpv_code":{"type":"string","title":"Tender Cpv Code","description":"Primary CPV classification code (e.g. \"55000000\")","default":""},"tender_market_type":{"type":"string","title":"Tender Market Type","description":"Market type as published (e.g. \"services\", \"travaux\")","default":""},"tender_nature":{"type":"string","title":"Tender Nature","description":"Notice nature as published by the source","default":""},"tender_submission_url":{"type":"string","title":"Tender Submission Url","description":"Direct URL to the submission platform, when the notice carries one","default":""},"tender_source":{"type":"string","title":"Tender Source","description":"Publication source: \"boamp\" (French) or \"ted\" (European)","default":""},"buyer_siren":{"type":"string","title":"Buyer Siren","description":"SIREN of the contracting authority (French notices)","default":""},"buyer_city":{"type":"string","title":"Buyer City","description":"City of the contracting authority","default":""},"buyer_website":{"type":"string","title":"Buyer Website","description":"Website of the contracting authority","default":""},"buyer_contact_email":{"type":"string","title":"Buyer Contact Email","description":"Contact email published on the notice for this procurement","default":""},"buyer_contact_phone":{"type":"string","title":"Buyer Contact Phone","description":"Contact phone published on the notice for this procurement","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPublicTendersWatchlistSignal","description":"Signal info for a tender at a WATCHED buyer.\n\nIdentical to the open Public Tenders block. Declared separately for the same\nreason its payload is: a shared ``$ref`` would name both signals' type after\nwhichever was declared first."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookPublicTendersWatchlistPayload","description":"Webhook payload for public_tenders_watchlist.\n\nSame shape as the open Public Tenders signal — one company-level lead per\nmatching notice, the buyer being the company — but declared as its own model\nrather than reusing that one. A shared ``$ref`` makes a generated client name\nBOTH signals' payload after whichever declared it first, so integrators of\nthis signal would find their type named after a signal they never\nsubscribed to.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marchespublics@example.fr","first_name":"","last_name":"","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"29","matched_persona":"","phone":"+33 2 98 98 89 89","sales_navigator_profile_url":"","title":""},"signal":{"buyer_city":"Quimper","buyer_contact_email":"marches@example.com","buyer_contact_phone":"","buyer_siren":"212900195","buyer_website":"https://www.quimper.bzh","id":"f6a7b8c9-d0e1-4f2a-b3c4-d5e6f7a8b9c0","job_offer_date":"2026-08-16","job_offer_description":"","job_offer_location":"29","job_offer_published_date":"2026-08-16","job_offer_source":"BOAMP","job_offer_title":"Fourniture et livraison de materiel scenique","job_offer_url":"https://www.boamp.fr/avis/detail/26-80902","last_signal":"Public Tenders Watchlist","last_signal_date":"2026-08-17","matched_keywords":"materiel scenique","name":"Tenders from my accounts","tender_cpv_code":"31500000","tender_deadline":"2026-09-15T12:00:00+00:00","tender_description":"Fourniture et livraison de materiel scenique pour l'equipement du centre culturel municipal.","tender_market_type":"fournitures","tender_nature":"cn-standard","tender_published_date":"2026-08-16T02:00:00+00:00","tender_source":"boamp","tender_submission_url":"","type":"public_tenders_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/recruitment-campaign":{"post":{"tags":["Signals"],"summary":"Create Recruitment Campaign signal","description":"Find companies running an active hiring push — those with multiple open job postings that match the roles, locations, and filters you care about. Identify HR leaders and talent teams before your competitors do.\n\n**Input:** job titles to match or exclude (`jobTitleInclude`/`jobTitleExclude`), locations (`locations` — optional, empty means worldwide — and `excludedLocations`), company size filters (`companySizeFilters`), the matching-job-count band a company must fall in (`minJobCount` — e.g. 10 open postings — and an optional `maxJobCount` cap), and job posting recency (`publishedDate`: \"24h\", \"7d\", \"30d\"). To resolve individual decision-makers, set `enablePersonaTargeting: true` and list the roles you want in `targetPersonas` (e.g. \"HR Director\", \"Talent Acquisition\"), capping how many contacts each company yields with `maxLeadsPerCompany` (1-50; **omit it and the default is 10% of company headcount, minimum 1**), and `companyOnlyWhenContactsRefused` (default false) to still receive the company, with no contact, when every candidate found there was filtered out rather than nothing. Optional enrichments (`getEmails`, `getPhones`, `detectTechnologies`, `getHomepageContent`) add a per-lead cost.\n\n**Output:** one lead per qualifying company delivered to your `webhookUrl` — this is a company-level signal, not one lead per job posting. Each lead includes the company name and website. When persona targeting is enabled, a matched HR/talent decision-maker is resolved and delivered as the `contact`; otherwise `contact` is null. Companies outside your filters are excluded server-side and never sent. **Note on `locations`:** it is optional — omit it or send an empty list to search **worldwide**. Multiple locations are combined with OR, so each one you add widens the search. Pass names (`\"France\"`), not ids; an unrecognised name returns 400 `INVALID_LOCATION`. Worldwide signals can match a lot more, so size `dailyLeadLimit` accordingly.\n\n**Use cases:**\n- Growth-account targeting — aggressive hiring = a scaling company with budget; prioritise it for outbound.\n- Function-specific pitch — many sales hires → GTM tooling; many eng hires → dev tooling.","operationId":"create_recruitment_campaign_signal_api_v1_signals_recruitment_campaign_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecruitmentCampaignCreate"},"examples":{"example1":{"summary":"Companies hiring aggressively","value":{"name":"Companies hiring aggressively","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"jobTitleInclude":["Engineer","Developer"],"jobTitleExclude":[],"jobTitleIncludeAll":false,"jobDescriptionInclude":[],"jobDescriptionExclude":[],"jobDescriptionIncludeAll":false,"locations":["France"],"companySizeFilters":["201-500","501-1000"],"excludedWebsites":["acme.com"],"publishedDate":"30d","minJobCount":10,"maxJobCount":1000,"enablePersonaTargeting":true,"targetPersonas":["HR Director","Talent Acquisition"],"customPersonaTitles":["People Operations Manager"],"personaExportMode":"top_ranked","personaLocations":["France"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies hiring aggressively","status":"active","signalTypeId":"recruitment_campaign","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"jobTitleInclude":["Engineer","Developer"],"jobTitleExclude":[],"jobTitleIncludeAll":false,"jobDescriptionInclude":[],"jobDescriptionExclude":[],"jobDescriptionIncludeAll":false,"locations":["France"],"companySizeFilters":["201-500","501-1000"],"excludedWebsites":["acme.com"],"publishedDate":"30d","minJobCount":10,"maxJobCount":1000,"enablePersonaTargeting":true,"targetPersonas":["HR Director","Talent Acquisition"],"customPersonaTitles":["People Operations Manager"],"personaExportMode":"top_ranked","personaLocations":["France"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: an unrecognized location filter","content":{"application/json":{"examples":{"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching job is found. `contact` is null unless persona targeting is enabled.","operationId":"job_lead_webhook_recruitment_campaign","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookRecruitmentCampaignPayload","description":"Webhook payload for the recruitment_campaign signal (one lead per company\nrunning an active hiring push).","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"HR Director","phone":"","sales_navigator_profile_url":"","title":"Head of Talent"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-18","job_offer_description":"One of 12 open roles at this company in the last 30 days...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-18","job_offer_source":"LinkedIn","job_offer_title":"Business Developer Junior","job_offer_url":"https://www.linkedin.com/jobs/view/4425589980","last_signal":"Recruitment Campaign","last_signal_date":"2026-05-31","matched_keywords":"Sales,Business Developer","name":"Companies in a hiring surge","type":"recruitment_campaign"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookRecruitmentCampaignPayload","description":"Webhook payload for the recruitment_campaign signal (one lead per company\nrunning an active hiring push).","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"HR Director","phone":"","sales_navigator_profile_url":"","title":"Head of Talent"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-18","job_offer_description":"One of 12 open roles at this company in the last 30 days...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-18","job_offer_source":"LinkedIn","job_offer_title":"Business Developer Junior","job_offer_url":"https://www.linkedin.com/jobs/view/4425589980","last_signal":"Recruitment Campaign","last_signal_date":"2026-05-31","matched_keywords":"Sales,Business Developer","name":"Companies in a hiring surge","type":"recruitment_campaign"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/recruitment-campaign-watchlist":{"post":{"tags":["Signals"],"summary":"Create Recruitment Campaign Watchlist signal","description":"Watch a fixed list of companies and get told when one of them starts hiring in VOLUME - the moment an account staffs up is the moment budget and headcount have just been approved, which is usually the same meeting your budget comes out of.\n\nTwo signals sit either side of this one. The Recruitment Campaign signal DISCOVERS companies from filters, where this one starts from your list. The Job Offers Watchlist fires on any single new posting at a company you watch, where this one fires only on a hiring PUSH - a company qualifies only once it has at least `minJobCount` open roles matching your filters inside the `publishedDate` window. That threshold is the whole point: one open role is noise, ten is a plan.\n\n**Input:** `companies` (a name, a domain, or a LinkedIn company URL per entry, or an object `{name, domain, linkedinUrl}` carrying all three), `minJobCount` and optional `maxJobCount` (the volume band that qualifies a company), `publishedDate` (the recency window the roles must fall in, e.g. `30d`), plus the usual `jobTitleInclude` / `jobTitleExclude`, `locations` and `companySizeFilters` filters, optional persona targeting (`enablePersonaTargeting`, `targetPersonas`, `companyOnlyWhenContactsRefused` - default false, still deliver the company, with no contact, when every candidate found there was filtered out instead of nothing) and enrichment flags (`getEmails`, `getPhones`).\n\n**Output:** one COMPANY-level lead per qualifying company - not one per posting. Each is pushed to your `webhookUrl` with a `signal` object carrying one of the open roles as the evidence, a `company` object, and `contact` empty. Turn persona targeting on and the decision-makers matching your `targetPersonas` are resolved at each company and delivered as person-leads instead.\n\nOnly companies that resolve to a WEBSITE are watched: the filtering happens at the job-data source, which matches companies on their domain. An entry given as a bare name starts contributing once its domain resolves, and until then it is listed but not matched. `GET /api/v1/watchlists/{signalId}/companies` is the one place that shows what is actually being watched - check it first if the signal delivers less than you expected.\n\n`companies` is consumed into the watchlist, so it is NOT echoed back in the `config` of this or any later response - the watched list has exactly one home. Add or remove companies with `POST` / `DELETE` on `/api/v1/watchlists/{signalId}/companies`; an edit re-scopes what is monitored automatically, with no need to recreate the signal.\n\n**Use cases:**\n- Budget-approved timing on named accounts - a company hiring ten roles at once has just had headcount signed off, which is the same meeting your budget comes out of; the volume is the qualifier a single posting cannot give you.\n- Scaling customers, not just new ones - watch your own base and treat a hiring push as the moment a team outgrows the plan it is on, ahead of the renewal conversation.\n- Sell to the build-out - recruiters, staffing, onboarding, equipment, workspace and payroll all have a buying window that opens when the campaign starts, not when the seats are filled.\n- Competitor momentum - a competitor staffing a whole function tells you where they are betting, early enough to answer it.","operationId":"create_recruitment_campaign_watchlist_signal_api_v1_signals_recruitment_campaign_watchlist_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/RecruitmentCampaignWatchlistConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"RecruitmentCampaignWatchlistCreate","examples":[{"config":{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"maxJobCount":1000,"minJobCount":10,"publishedDate":"30d","targetPersonas":["__best_fitting__"]},"dailyLeadLimit":25,"name":"Hiring pushes at my accounts","status":"active","webhookUrl":"https://example.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Hiring pushes at my accounts","value":{"name":"Hiring pushes at my accounts","webhookUrl":"https://example.com/webhooks/rodz","dailyLeadLimit":25,"status":"active","config":{"companies":["Doctolib",{"name":"PayFit","domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit"},"lemlist"],"minJobCount":10,"maxJobCount":1000,"publishedDate":"30d","enablePersonaTargeting":true,"targetPersonas":["__best_fitting__"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Hiring pushes at my accounts","status":"active","signalTypeId":"recruitment_campaign_watchlist","webhookUrl":"https://example.com/webhooks/rodz","config":{"minJobCount":10,"maxJobCount":1000,"publishedDate":"30d","enablePersonaTargeting":true,"targetPersonas":["__best_fitting__"],"getEmails":true},"dailyLeadLimit":25,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","watchlist":{"watched":3,"rejected":0,"alreadyWatched":0},"applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Sent once per watched company that qualifies as running a hiring push. One of its open roles is carried as the evidence.","operationId":"recruitment_campaign_watchlist_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookRecruitmentCampaignWatchlistPayload","description":"Webhook payload for recruitment_campaign_watchlist.\n\nSame shape as the discovery signal above — one lead per company running a\nhiring push — but declared as its own model rather than reusing that one.\nA shared ``$ref`` makes a generated client name BOTH signals' payload after\nwhichever declared it first, so integrators of this signal would find their\ntype called after a signal they never subscribed to.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"HR Director","phone":"","sales_navigator_profile_url":"","title":"Head of Talent"},"signal":{"id":"e5f6a7b8-c9d0-4e1f-a2b3-c4d5e6f7a8b9","job_offer_date":"2026-08-12","job_offer_description":"One of 14 open roles at this company in the last 30 days...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-08-12","job_offer_source":"LinkedIn","job_offer_title":"Account Executive","job_offer_url":"https://www.linkedin.com/jobs/view/4425589980","last_signal":"Recruitment Campaign Watchlist","last_signal_date":"2026-08-15","matched_keywords":"Account Executive,Sales","name":"Hiring pushes at my accounts","type":"recruitment_campaign_watchlist"}}]},"example":{"signal":{"id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","name":"Hiring pushes at my accounts","type":"recruitment_campaign_watchlist","last_signal":"Recruitment Campaign Watchlist","last_signal_date":"2026-08-15","job_offer_url":"https://www.linkedin.com/jobs/view/4425589980","job_offer_title":"Account Executive","job_offer_location":"Paris, Ile-de-France, France","job_offer_description":"One of 14 open roles at this company in the last 30 days...","job_offer_date":"2026-08-12","job_offer_source":"LinkedIn","matched_keywords":"Account Executive,Sales"},"contact":"","company":{"name":"lemlist","website":"https://lemlist.com","linkedin_url":"https://www.linkedin.com/company/lemlist","industry":"Software Development","location":"Paris, France","hq_country_code":"FR","hq_city":"Paris","employee_count":"","employee_range":"51-200"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookRecruitmentCampaignWatchlistPayload","description":"Webhook payload for recruitment_campaign_watchlist.\n\nSame shape as the discovery signal above — one lead per company running a\nhiring push — but declared as its own model rather than reusing that one.\nA shared ``$ref`` makes a generated client name BOTH signals' payload after\nwhichever declared it first, so integrators of this signal would find their\ntype called after a signal they never subscribed to.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"HR Director","phone":"","sales_navigator_profile_url":"","title":"Head of Talent"},"signal":{"id":"e5f6a7b8-c9d0-4e1f-a2b3-c4d5e6f7a8b9","job_offer_date":"2026-08-12","job_offer_description":"One of 14 open roles at this company in the last 30 days...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-08-12","job_offer_source":"LinkedIn","job_offer_title":"Account Executive","job_offer_url":"https://www.linkedin.com/jobs/view/4425589980","last_signal":"Recruitment Campaign Watchlist","last_signal_date":"2026-08-15","matched_keywords":"Account Executive,Sales","name":"Hiring pushes at my accounts","type":"recruitment_campaign_watchlist"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/republished-job-offers":{"post":{"tags":["Signals"],"summary":"Create Republished Job Offers signal","description":"Capture hiring desperation — companies republishing the same roles repeatedly signal serious talent shortages, high hiring urgency, and concentrated opportunity.\n\n**Input:** job title keywords (`jobTitleInclude`, `jobTitleExclude`), target locations (`locations` — optional, empty means worldwide) and excluded locations, `companySizeFilters`, a job recency window (`publishedDate` — only jobs posted within the last \"24h\", \"7d\", or \"30d\"), email enrichment toggle (`getEmails`), and optionally hiring decision-makers (`enablePersonaTargeting` with `targetPersonas`, `customPersonaTitles`, and `maxLeadsPerCompany` — 1-50 contacts per company; **when omitted the default is 10% of company headcount, minimum 1**, so a large employer can yield many contacts from a single job — plus `companyOnlyWhenContactsRefused`, default false, to still get the company, with no contact, when every candidate found there was filtered out instead of nothing).\n\n**Output:** every matching republished job is delivered to your `webhookUrl` as it is detected, filtered by your config. Leads include hiring decision-maker contact details only when `enablePersonaTargeting` is enabled; otherwise the `contact` field is empty. **Note on `locations`:** it is optional — omit it or send an empty list to search **worldwide**. Multiple locations are combined with OR, so each one you add widens the search. Pass names (`\"France\"`), not ids; an unrecognised name returns 400 `INVALID_LOCATION`. Worldwide signals can match a lot more, so size `dailyLeadLimit` accordingly.\n\n**Use cases:**\n- Pain-point pitch — a re-posted role signals a hard-to-fill need; recruiting + automation vendors pitch relief.\n- Urgency timing — reach them while the hiring pain is acute.","operationId":"create_republished_job_offers_signal_api_v1_signals_republished_job_offers_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepublishedJobOffersCreate"},"examples":{"example1":{"summary":"Hard-to-fill engineering roles","value":{"name":"Hard-to-fill engineering roles","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"jobTitleInclude":["Engineer","Developer"],"jobTitleExclude":[],"jobTitleIncludeAll":false,"jobDescriptionInclude":[],"jobDescriptionExclude":[],"jobDescriptionIncludeAll":false,"locations":["France"],"companySizeFilters":["201-500","501-1000"],"excludedWebsites":["acme.com"],"publishedDate":"30d","enablePersonaTargeting":true,"targetPersonas":["CTO","HR Director"],"customPersonaTitles":["VP of Engineering"],"personaExportMode":"top_ranked","personaLocations":["France"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Hard-to-fill engineering roles","status":"active","signalTypeId":"republished_job_offers","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"jobTitleInclude":["Engineer","Developer"],"jobTitleExclude":[],"jobTitleIncludeAll":false,"jobDescriptionInclude":[],"jobDescriptionExclude":[],"jobDescriptionIncludeAll":false,"locations":["France"],"companySizeFilters":["201-500","501-1000"],"excludedWebsites":["acme.com"],"publishedDate":"30d","enablePersonaTargeting":true,"targetPersonas":["CTO","HR Director"],"customPersonaTitles":["VP of Engineering"],"personaExportMode":"top_ranked","personaLocations":["France"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: an unrecognized location filter","content":{"application/json":{"examples":{"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching job is found. `contact` is null unless persona targeting is enabled.","operationId":"job_lead_webhook_republished_job_offers","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookRepublishedJobOffersPayload","description":"Webhook payload for the republished_job_offers signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"CEO","phone":"","sales_navigator_profile_url":"","title":"Chief Executive Officer"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-20","job_offer_description":"Repeatedly republished role - the company is struggling to fill it...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-20","job_offer_source":"LinkedIn","job_offer_title":"Senior Account Executive France","job_offer_url":"https://www.linkedin.com/jobs/view/4415464373","last_signal":"Republished Job Offer","last_signal_date":"2026-05-31","matched_keywords":"Account Executive,CRO","name":"Hard-to-fill roles (republished)","type":"republished_job_offers"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookJobSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","company"],"title":"WebhookRepublishedJobOffersPayload","description":"Webhook payload for the republished_job_offers signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"CEO","phone":"","sales_navigator_profile_url":"","title":"Chief Executive Officer"},"signal":{"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","job_offer_date":"2026-05-20","job_offer_description":"Repeatedly republished role - the company is struggling to fill it...","job_offer_location":"Paris (France)","job_offer_published_date":"2026-05-20","job_offer_source":"LinkedIn","job_offer_title":"Senior Account Executive France","job_offer_url":"https://www.linkedin.com/jobs/view/4415464373","last_signal":"Republished Job Offer","last_signal_date":"2026-05-31","matched_keywords":"Account Executive,CRO","name":"Hard-to-fill roles (republished)","type":"republished_job_offers"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/social-mentions":{"post":{"tags":["Signals"],"summary":"Create Social Mentions signal","description":"Reach prospects who are actively talking about the topics you care about on LinkedIn. Track the keywords that matter to you and turn the people mentioning them — and the people engaging with those posts — into enriched leads.\n\n**Input:** keywords to track (`keywords`, plus `keywordExclude` to skip posts containing unwanted terms), which people on each matching post become leads (`engagementTypes`: the post author, and/or people who liked or commented), a minimum engagement threshold (`minEngagement`), the time window to monitor (`postedLimit`: `24h`, `week`, or `month`), and your ICP filters (`targetPersonas`, `customPersonaTitles`, `companySizeFilters`, `locations`, `industryFilters`, each with an exclusion variant), with optional enrichment (`getEmails`, `getPhones`).\n\n**Output:** every person matching your keywords and ICP config is pushed to your `webhookUrl` as an enriched lead — including the matched keywords, the LinkedIn post involved, their profile details (name, title, location, company), and enriched contact data when requested. Non-matching posts and people are filtered out. New mentions are picked up daily and delivered up to your `dailyLeadLimit` per day.\n\n**Use cases:**\n- Topic-led outreach — reach people discussing your problem space with a message tied to what they said.\n- Competitor-mention capture — catch people naming a competitor and offer an alternative.\n- Community building — join the conversation to build brand and inbound.","operationId":"create_social_mentions_signal_api_v1_signals_social_mentions_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/SocialMentionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"SocialMentionsCreate","description":"Create a Social Mentions signal.","examples":[{"config":{"companySizeFilters":[],"customPersonaTitles":[],"detectTechnologies":false,"engagementTypes":["likes","comments"],"excludedCompanySizeFilters":[],"excludedCompanyUrls":[],"excludedIndustryFilters":[],"excludedLocations":[],"excludedTitles":[],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"industryFilters":[],"keywordExclude":[],"keywords":["Rodz","lead tracker"],"locations":[],"maxPosts":0,"minEngagement":5,"postedLimit":"24h","targetPersonas":[]},"dailyLeadLimit":50,"name":"Brand mentions on LinkedIn","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Brand mentions on LinkedIn","value":{"name":"Brand mentions on LinkedIn","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"keywords":["Rodz","lead tracker"],"keywordExclude":[],"postedLimit":"24h","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"],"targetPersonas":[],"customPersonaTitles":[],"excludedTitles":[],"companySizeFilters":[],"excludedCompanySizeFilters":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanyUrls":[],"locations":[],"excludedLocations":[],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Brand mentions on LinkedIn","status":"active","signalTypeId":"social_mentions","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"keywords":["Rodz","lead tracker"],"keywordExclude":[],"postedLimit":"24h","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"],"targetPersonas":[],"customPersonaTitles":[],"excludedTitles":[],"companySizeFilters":[],"excludedCompanySizeFilters":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanyUrls":[],"locations":[],"excludedLocations":[],"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config (Keywords), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (Keywords)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["keywords"],"missing_field_labels":["Keywords"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"social_lead_webhook_social_mentions","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the contact whose engagement surfaced this post to us. For ``competitor_social_reactions``, this is the employee at the tracked competitor (one of the URLs in ``linkedinCompanyUrls``) whose like/comment bubbled the post up — use it to trace the lead back to a specific named buyer at the competitor. For social_mentions / social_reactions, this is the post author.","default":""},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the company whose engagement surfaced this lead. For ``competitor_social_reactions``, this is the entry from ``linkedinCompanyUrls`` that the ``tracked_contact`` works at. For other social signals, the company the system was monitoring.","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment or mention","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookSocialSignal","description":"Signal info for social signals (social_mentions, social_reactions,\ncompetitor_social_reactions, company_engagement, company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookSocialMentionsPayload","description":"Webhook payload for the social_mentions signal.\n\n`contact.title` is the person's LinkedIn HEADLINE as shown on the post, not\na structured job title; personas are judged on it by meaning.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"RevOps","phone":"","sales_navigator_profile_url":"","title":"Head of Revenue Operations"},"signal":{"engagement_type":"reaction","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Social Mention","last_signal_date":"2026-05-31","mention_content":"Reacted with LIKE","name":"People talking about RevOps","post_author_first_name":"Julien","post_author_last_name":"Moreau","post_content":"Most RevOps teams are still stitching tools together by hand. Here is how we cut it...","post_date":"2026-05-29","post_url":"https://www.linkedin.com/posts/post-author_revops-activity-7482778044735295489-bybl","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/post-author","type":"social_mentions"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the contact whose engagement surfaced this post to us. For ``competitor_social_reactions``, this is the employee at the tracked competitor (one of the URLs in ``linkedinCompanyUrls``) whose like/comment bubbled the post up — use it to trace the lead back to a specific named buyer at the competitor. For social_mentions / social_reactions, this is the post author.","default":""},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the company whose engagement surfaced this lead. For ``competitor_social_reactions``, this is the entry from ``linkedinCompanyUrls`` that the ``tracked_contact`` works at. For other social signals, the company the system was monitoring.","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment or mention","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookSocialSignal","description":"Signal info for social signals (social_mentions, social_reactions,\ncompetitor_social_reactions, company_engagement, company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookSocialMentionsPayload","description":"Webhook payload for the social_mentions signal.\n\n`contact.title` is the person's LinkedIn HEADLINE as shown on the post, not\na structured job title; personas are judged on it by meaning.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"RevOps","phone":"","sales_navigator_profile_url":"","title":"Head of Revenue Operations"},"signal":{"engagement_type":"reaction","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Social Mention","last_signal_date":"2026-05-31","mention_content":"Reacted with LIKE","name":"People talking about RevOps","post_author_first_name":"Julien","post_author_last_name":"Moreau","post_content":"Most RevOps teams are still stitching tools together by hand. Here is how we cut it...","post_date":"2026-05-29","post_url":"https://www.linkedin.com/posts/post-author_revops-activity-7482778044735295489-bybl","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/post-author","type":"social_mentions"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/social-reactions":{"post":{"tags":["Signals"],"summary":"Create Social Reactions signal","description":"Get the people engaging with your target LinkedIn posts — everyone who liked, commented, or (optionally) authored them. Use `engagementTypes` to control the mix: combine `\"likes\"` (reactions) + `\"comments\"` (commenters) + `\"poster\"` (author), or use `[\"poster\"]` alone for author-only leads. **Input:** LinkedIn post URLs (`postUrls`), engagement type selection, optional enrichment flags (`getEmails`, `getPhones`, `getSireneData`), and ICP filters (`targetPersonas`, `companySizeFilters`, `industryFilters`, `locations`, `excludedCompanyUrls`). **Output:** each person matching your engagement and filter criteria is pushed to your `webhookUrl` as an enriched lead; non-matching engagers are filtered out.\n\n**Use cases:**\n- Post-driven leads — turn a high-performing post (yours or a target's) into a warm lead list.\n- Warm follow-up — DM or email the people who engaged with a relevant post.","operationId":"create_social_reactions_signal_api_v1_signals_social_reactions_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/SocialReactionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"SocialReactionsCreate","description":"Create a Social Reactions signal.","examples":[{"config":{"companySizeFilters":[],"customPersonaTitles":[],"detectTechnologies":false,"engagementTypes":["likes","comments"],"excludedCompanySizeFilters":[],"excludedCompanyUrls":[],"excludedIndustryFilters":[],"excludedLocations":[],"excludedTitles":[],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"industryFilters":[],"locations":[],"maxPosts":0,"minEngagement":5,"postUrls":["https://linkedin.com/feed/update/urn:li:activity:123456"],"postedLimit":"week","targetPersonas":[]},"dailyLeadLimit":50,"name":"Reactions on key posts","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Reactions on key posts","value":{"name":"Reactions on key posts","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"postUrls":["https://linkedin.com/feed/update/urn:li:activity:123456"],"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanySizeFilters":[],"excludedTitles":[],"excludedCompanyUrls":[],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Reactions on key posts","status":"active","signalTypeId":"social_reactions","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"getEmails":true,"getPhones":false,"getSireneData":false,"detectTechnologies":false,"getHomepageContent":false,"postUrls":["https://linkedin.com/feed/update/urn:li:activity:123456"],"companySizeFilters":[],"targetPersonas":[],"customPersonaTitles":[],"locations":[],"excludedLocations":[],"industryFilters":[],"excludedIndustryFilters":[],"excludedCompanySizeFilters":[],"excludedTitles":[],"excludedCompanyUrls":[],"postedLimit":"week","minEngagement":5,"maxPosts":0,"engagementTypes":["likes","comments"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config (Post URLs), or an unrecognized location","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active (Post URLs)","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["post_urls"],"missing_field_labels":["Post URLs"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a new lead is detected.","operationId":"social_lead_webhook_social_reactions","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the contact whose engagement surfaced this post to us. For ``competitor_social_reactions``, this is the employee at the tracked competitor (one of the URLs in ``linkedinCompanyUrls``) whose like/comment bubbled the post up — use it to trace the lead back to a specific named buyer at the competitor. For social_mentions / social_reactions, this is the post author.","default":""},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the company whose engagement surfaced this lead. For ``competitor_social_reactions``, this is the entry from ``linkedinCompanyUrls`` that the ``tracked_contact`` works at. For other social signals, the company the system was monitoring.","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment or mention","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookSocialSignal","description":"Signal info for social signals (social_mentions, social_reactions,\ncompetitor_social_reactions, company_engagement, company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookSocialReactionsPayload","description":"Webhook payload for the social_reactions signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"HR Director","phone":"","sales_navigator_profile_url":"","title":"HR Director"},"signal":{"engagement_type":"comment","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Social Reaction","last_signal_date":"2026-05-31","mention_content":"Congrats to the whole team - huge milestone!","name":"Engagers on my target posts","post_author_first_name":"Julien","post_author_last_name":"Moreau","post_content":"We just shipped our biggest release of the year...","post_date":"2026-05-30","post_url":"https://www.linkedin.com/posts/post-author_hiring-activity-7470030745718235136-lUZE","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/post-author","type":"social_reactions"}}]}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_contact":{"type":"string","title":"Tracked Contact","description":"LinkedIn profile URL of the contact whose engagement surfaced this post to us. For ``competitor_social_reactions``, this is the employee at the tracked competitor (one of the URLs in ``linkedinCompanyUrls``) whose like/comment bubbled the post up — use it to trace the lead back to a specific named buyer at the competitor. For social_mentions / social_reactions, this is the post author.","default":""},"tracked_company":{"type":"string","title":"Tracked Company","description":"LinkedIn URL of the company whose engagement surfaced this lead. For ``competitor_social_reactions``, this is the entry from ``linkedinCompanyUrls`` that the ``tracked_contact`` works at. For other social signals, the company the system was monitoring.","default":""},"post_url":{"type":"string","title":"Post Url","description":"LinkedIn post URL","default":""},"post_date":{"type":"string","title":"Post Date","description":"Day the post was published, `YYYY-MM-DD` — the event date, not the day the engagement was delivered (`last_signal_date`). \"\" when unknown.","default":""},"engagement_type":{"type":"string","title":"Engagement Type","description":"Engagement type (e.g. \"like\", \"comment\")","default":""},"post_content":{"type":"string","title":"Post Content","description":"Full body text of the LinkedIn post (up to 2000 chars)","default":""},"mention_content":{"type":"string","title":"Mention Content","description":"Text of the lead's comment or mention","default":""},"post_author_first_name":{"type":"string","title":"Post Author First Name","description":"First name of the LinkedIn post author","default":""},"post_author_last_name":{"type":"string","title":"Post Author Last Name","description":"Last name of the LinkedIn post author","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookSocialSignal","description":"Signal info for social signals (social_mentions, social_reactions,\ncompetitor_social_reactions, company_engagement, company_post_reactions)."},"contact":{"$ref":"#/components/schemas/WebhookContact"},"company":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyPerson","description":"Company block delivered on **person-based** leads (competitor, job_changes,\nevent_attendees, social/engagement signals).\n\nPerson leads always carry the complete company object: the basic identity +\nhomepage/tech enrichment (from ``WebhookCompanyBasic``), the firmographics\n(``industry``/``location``/``employee_count``/``employee_range`` from\n``WebhookCompanyFull``), AND a short company ``description``. Every key is\nalways present; unavailable values are the empty string ``\"\"``. Firmographic\nfields populate when the lead's company is resolved (e.g. when you filter by\ncompany size or industry); the enrichment fields (``tech_stack``,\n``homepage_title``, ``meta_description``) populate only when the matching\nenrichment is enabled on the signal."}},"type":"object","required":["signal","contact","company"],"title":"WebhookSocialReactionsPayload","description":"Webhook payload for the social_reactions signal.","examples":[{"company":{"description":"B2B SaaS platform for supply-chain analytics.","employee_count":320,"employee_range":"201-500","homepage_title":"Tech Corp - Supply-chain analytics","hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://linkedin.com/company/techcorp","location":"Paris, France","meta_description":"Real-time analytics for modern supply chains.","name":"Tech Corp","tech_stack":["HubSpot","Segment","AWS"],"website":"https://techcorp.com"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-05-31T14:30:00+00:00","email":"marie.dupont@techcorp.com","first_name":"Marie","last_name":"Dupont","lead_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"HR Director","phone":"","sales_navigator_profile_url":"","title":"HR Director"},"signal":{"engagement_type":"comment","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Social Reaction","last_signal_date":"2026-05-31","mention_content":"Congrats to the whole team - huge milestone!","name":"Engagers on my target posts","post_author_first_name":"Julien","post_author_last_name":"Moreau","post_content":"We just shipped our biggest release of the year...","post_date":"2026-05-30","post_url":"https://www.linkedin.com/posts/post-author_hiring-activity-7470030745718235136-lUZE","tracked_company":"","tracked_contact":"https://www.linkedin.com/in/post-author","type":"social_reactions"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/tech-adoption":{"post":{"tags":["Signals"],"summary":"Create Tech Adoption signal","description":"Reach companies the month they start using a tool you integrate with or complement — while the rollout budget is still open and the stack is still being decided.\n\n**Input:** `trackedTool` (a `vendorName`) or `trackedCategory` (a `category`), both copied verbatim from GET /api/v1/signals/technographic-tools — at least one is required; a name outside that catalog finds nothing and is flagged in `warnings`. Narrow with `companyEmployeeSizeRanges`, `companyIndustries`, `companyCountries` (ISO 3166-1 alpha-2) and `companyRegion`. `enablePersonaTargeting` with `targetPersonas` finds the matching people at each company; `getEmails` then adds their email.\n\n**Output:** company-level leads — company name, domain, LinkedIn URL, industry, size, country — plus the detected tool and the change date. Contacts are delivered only when persona lookup or enrichment is enabled.\n\n**Use cases:**\n- *Integration play* — a company adopts a tool you plug into; pitch the connector while they are still wiring it up.\n- *Complementary sell* — a new CRM means new needs around it (enrichment, routing, analytics).\n- *Displacement watch* — pair with Tech Displacement to catch both sides of a migration.","operationId":"create_tech_adoption_signal_api_v1_signals_tech_adoption_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/TechAdoptionConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"TechAdoptionCreate","examples":[{"config":{"companyCountries":["FR"],"companyEmployeeSizeRanges":["51-200"],"getEmails":true,"trackedTool":"Hubspot Sales Hub"},"dailyLeadLimit":50,"name":"Companies adopting HubSpot Sales Hub (FR, 51-200)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies adopting HubSpot Sales Hub (FR, 51-200)","value":{"name":"Companies adopting HubSpot Sales Hub (FR, 51-200)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"trackedTool":"Hubspot Sales Hub","companyCountries":["FR"],"companyEmployeeSizeRanges":["51-200"],"getEmails":true}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies adopting HubSpot Sales Hub (FR, 51-200)","status":"active","signalTypeId":"tech_adoption","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"trackedTool":"Hubspot Sales Hub","companyCountries":["FR"],"companyEmployeeSizeRanges":["51-200"],"getEmails":true},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching company is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. The `job_offer_*` keys belong to the shared company-lead envelope and are always empty for this signal.","operationId":"tech_adoption_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies adopting HubSpot (FR, 51-200)","type":"tech_adoption","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":"","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","competitor":""},"contact":"","company":{"name":"Datalyz","website":"https://datalyz.io","linkedin_url":"https://www.linkedin.com/company/datalyz","industry":"Software Development","location":"France","hq_country_code":"FR","hq_city":"","employee_count":"","employee_range":"51-200"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/tech-displacement":{"post":{"tags":["Signals"],"summary":"Create Tech Displacement signal","description":"Reach companies the month they DROP a tool — the clearest buying window there is, because they have already decided the incumbent is not working.\n\n**Input:** identical to Tech Adoption — `trackedTool` or `trackedCategory` (one required), plus the firmographic filters. Here the tool you name is the one being abandoned, typically a competitor.\n\n**Output:** company-level leads with the dropped tool and the change date.\n\n**Use cases:**\n- *Competitor churn* — they just removed your rival; you are pitching a replacement, not a change of mind.\n- *Re-engagement* — a prospect who once chose against you drops that tool.\n- *Stack consolidation* — dropping a point solution often means a platform decision is underway.","operationId":"create_tech_displacement_signal_api_v1_signals_tech_displacement_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/TechAdoptionConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"TechDisplacementCreate","examples":[{"config":{"companyCountries":["US"],"companyEmployeeSizeRanges":["201-500"],"trackedTool":"Salesforce CRM"},"dailyLeadLimit":50,"name":"Companies dropping Salesforce (US, 201-500)","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"examples":{"example1":{"summary":"Companies dropping Salesforce (US, 201-500)","value":{"name":"Companies dropping Salesforce (US, 201-500)","webhookUrl":"https://your-server.com/webhooks/rodz","dailyLeadLimit":50,"status":"active","config":{"trackedTool":"Salesforce CRM","companyCountries":["US"],"companyEmployeeSizeRanges":["201-500"]}}}}}},"required":true},"responses":{"201":{"description":"Signal created","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies dropping Salesforce (US, 201-500)","status":"active","signalTypeId":"tech_displacement","webhookUrl":"https://your-server.com/webhooks/rodz","config":{"trackedTool":"Salesforce CRM","companyCountries":["US"],"companyEmployeeSizeRanges":["201-500"]},"dailyLeadLimit":50,"leadsToday":0,"leadsTotal":0,"duplicateHandling":"refuse","createdAt":"2026-05-31T14:30:00+00:00","updatedAt":"2026-05-31T14:30:00+00:00","applied":{},"warnings":[]}}}},"400":{"description":"Invalid request: missing required config, or an unrecognized location filter","content":{"application/json":{"examples":{"missing_required_fields":{"summary":"Missing required config when creating as active","value":{"error":{"code":"MISSING_REQUIRED_FIELDS","message":"Cannot activate signal: missing required fields","missing_fields":["<field>"],"missing_field_labels":["<Field label>"]}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"INVALID_API_KEY","message":"Invalid or revoked API key"}}}}},"402":{"description":"Account has no credits","content":{"application/json":{"example":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Cannot activate signal: account has no credits"}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}}},"callbacks":{"_webhook":{"{$request.body#/webhookUrl}":{"post":{"summary":" Webhook","description":"Payload sent to your webhookUrl when a matching company is detected. Company-only: `contact` is the empty string \"\" unless persona targeting is enabled. The `job_offer_*` keys belong to the shared company-lead envelope and are always empty for this signal.","operationId":"tech_displacement_webhook","requestBody":{"content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]},"example":{"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Companies dropping Salesforce (US)","type":"tech_displacement","last_signal":"Tech Displacement","last_signal_date":"2026-07-30","job_offer_url":"","job_offer_title":"","job_offer_location":"","job_offer_description":"","job_offer_date":"","job_offer_source":"","matched_keywords":"","technology":"Salesforce CRM","technology_category":"CRM","technology_change_date":"2026-07-29","competitor":""},"contact":"","company":{"name":"Northwind Logistics","website":"https://northwind-logistics.com","linkedin_url":"https://www.linkedin.com/company/northwind-logistics","industry":"Transportation","location":"United States","hq_country_code":"US","hq_city":"","employee_count":"","employee_range":"201-500"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""},"technology":{"type":"string","title":"Technology","description":"The technology the company adopted, dropped or uses (e.g. \"HubSpot Sales Hub\"). For competitor_customer, the tracked tool. \"\" when unknown.","default":""},"technology_category":{"type":"string","title":"Technology Category","description":"Category of that technology (e.g. \"CRM\"); \"\" when unknown.","default":""},"technology_change_date":{"type":"string","title":"Technology Change Date","description":"When the adoption (tech_adoption, ai_adoption) or the drop (tech_displacement) was detected. \"\" for competitor_customer, which reports current usage rather than a change.","default":""},"competitor":{"type":"string","title":"Competitor","description":"competitor_customer only: the tracked competitor tool this company uses. \"\" on the other technographic signals.","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookTechnographicSignal","description":"Signal block of a technographic lead: the technology the event is about."},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookTechnographicPayload","description":"Webhook payload for the technographic signals (tech_adoption,\ntech_displacement, ai_adoption, competitor_customer).\n\nCompany-only: ``contact`` is the empty string ``\"\"`` unless persona\ntargeting is enabled, in which case it is a contact object. All documented\nkeys are always present; absent values are empty strings, never ``null``.\n\nThe ``job_offer_*`` keys are part of the shared company-lead envelope and\nare always empty here — these signals carry no job posting. They are\ndocumented rather than hidden because they DO arrive on the wire, and a\nconsumer parsing strictly would otherwise trip on them.\n\nThe example below is a real payload captured from the production push path\non 2026-07-30, not a hand-written approximation.","examples":[{"company":{"employee_count":"","employee_range":"51-200","hq_city":"","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/datalyz","location":"France","name":"Datalyz","website":"https://datalyz.io"},"contact":"","signal":{"competitor":"","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","job_offer_date":"","job_offer_description":"","job_offer_location":"","job_offer_published_date":"","job_offer_source":"","job_offer_title":"","job_offer_url":"","last_signal":"Tech Adoption","last_signal_date":"2026-07-30","matched_keywords":"","name":"Companies adopting HubSpot (FR, 51-200)","technology":"HubSpot Sales Hub","technology_category":"CRM","technology_change_date":"2026-07-29","type":"tech_adoption"}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals/technographic-industries":{"get":{"tags":["Signals"],"summary":"List technographic industries (deprecated — use /signals/industries)","description":"Get the exact industry names accepted by `companyIndustries` on a technographic signal, so an integration can build a valid filter instead of guessing at spelling.\n\n**Input:** `search` (substring match, optional) and `limit` (1-200, default 50). Omit both to page through the full vocabulary.\n\n**Output:** `industries[]` — plain strings, to be sent verbatim in `config.companyIndustries`.\n\nThese values come from a fixed vocabulary: an unrecognised string is not an error, it simply matches no company, so the signal is created successfully and then produces nothing. Always source the value here rather than typing it. Free — consumes no credits.","operationId":"list_technographic_industries_public_api_v1_signals_technographic_industries_get","deprecated":true,"security":[{"BearerAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Substring match on the industry name.","default":"","title":"Search"},"description":"Substring match on the industry name."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Maximum industries to return.","default":50,"title":"Limit"},"description":"Maximum industries to return."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"industries":{"items":{"type":"string"},"type":"array","title":"Industries","description":"Matching industry names."}},"type":"object","required":["industries"],"title":"PublicTechIndustriesResponse","examples":[{"industries":["Financial Services","Software Development"]}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"search","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/technographic-tools":{"get":{"tags":["Signals"],"summary":"List trackable tools for technographic signals","description":"Discover which software you can build a technographic signal around, and get the exact identifier to send when you create one — so an integration can configure these signals end-to-end without a human copying names out of the UI.\n\n**Input:** `search` (substring match on tool name or category, optional), `category` (restrict to one category, optional), and `limit` (1-200, default 50).\n\n**Output:** `tools[]`, each with `name`, `vendorName` (the exact string to pass as `trackedTool`), `category` (pass as `trackedCategory` to watch every tool in it), `upperCategory`, `url`, and `supportsDisplacement`.\n\nFeeds `trackedTool` / `trackedCategory` on **Tech Adoption**, **AI Adoption**, **Tech Displacement** and **Competitor Customers**. Only create a Tech Displacement signal for a tool whose `supportsDisplacement` is `true`. This endpoint is free and consumes no credits.","operationId":"list_technographic_tools_public_api_v1_signals_technographic_tools_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Substring match on tool name or category.","default":"","title":"Search"},"description":"Substring match on tool name or category."},{"name":"category","in":"query","required":false,"schema":{"type":"string","description":"Restrict to a single category, e.g. `crm`.","default":"","title":"Category"},"description":"Restrict to a single category, e.g. `crm`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Maximum tools to return.","default":50,"title":"Limit"},"description":"Maximum tools to return."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"tools":{"items":{"properties":{"name":{"type":"string","title":"Name","description":"Display name of the tool, e.g. `HubSpot`."},"vendorName":{"type":"string","title":"Vendorname","description":"The exact value to send as `trackedTool` when creating a technographic signal. Always copy this verbatim — a near-miss like `Hubspot` matches nothing and the signal produces no leads."},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Tool category, e.g. `crm`. Send as `trackedCategory` to watch a whole category."},"upperCategory":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uppercategory","description":"Broader grouping, e.g. `Sales & Marketing`."},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"The tool vendor's own website."},"supportsDisplacement":{"type":"boolean","title":"Supportsdisplacement","description":"Whether churn away from this tool is tracked. `false` means a Tech Displacement signal on this tool can never fire — check this before creating one.","default":false}},"type":"object","required":["name","vendorName"],"title":"PublicTechTool","description":"One trackable tool in the technographic catalog.","examples":[{"category":"crm","name":"HubSpot","supportsDisplacement":true,"upperCategory":"Sales & Marketing","url":"hubspot.com","vendorName":"HubSpot"}]},"type":"array","title":"Tools","description":"Matching tools."}},"type":"object","required":["tools"],"title":"PublicTechToolsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"search","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signalId}/mutual-connections":{"get":{"tags":["Signals"],"summary":"Get a Mutual Connections signal's progress","description":"See how far a Mutual Connections signal has got: how much of each of the two networks has been read, how many people were found in both, and how many have been delivered.\n\n**Input:** `signalId` in the path.\n\n**Output:** `profiles` (per profile: `state`, `peopleRead`), `mutualsFound`, `mutualCountKnown` — the number of mutual connections is only final once both networks have been read — and `oneTimeExtract` progress.","operationId":"get_mutual_connections_progress_api_v1_signals__signalId__mutual_connections_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the Mutual Connections signal, as returned by the create endpoint.","examples":["c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f"],"title":"Signalid"},"description":"Id of the Mutual Connections signal, as returned by the create endpoint."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"profiles":{"items":{"properties":{"url":{"type":"string","title":"Url","description":"The profile's LinkedIn URL, as configured."},"state":{"type":"string","title":"State","description":"`waiting` (not readable yet), `reading` (their network is being read), `done` (read to the end; new connections only from now on), `not_visible` (they hide their connection list), `declined` (cannot be read)."},"peopleRead":{"type":"integer","title":"Peopleread","description":"People of this profile's network read so far.","default":0}},"type":"object","required":["url","state"],"title":"MutualProfileStatus","description":"Where one of the two compared profiles stands."},"type":"array","title":"Profiles"},"mutualsFound":{"type":"integer","title":"Mutualsfound","description":"People found in both networks so far, before your persona filter. Grows until both networks are read.","default":0},"mutualCountKnown":{"type":"boolean","title":"Mutualcountknown","description":"True once both networks have been read (or cannot be).","default":false},"oneTimeExtract":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Onetimeextract","description":"`target`, `delivered`, `status` (`running` / `complete` / `none`)."}},"type":"object","title":"MutualConnectionsStatus","description":"Both profiles, the mutual connections found, and delivery progress.","examples":[{"mutualCountKnown":false,"mutualsFound":38,"oneTimeExtract":{"dailyNewConnections":true,"delivered":12,"status":"running","target":100},"profiles":[{"peopleRead":1146,"state":"done","url":"https://www.linkedin.com/in/claire-martin-cfo/"},{"peopleRead":450,"state":"reading","url":"https://www.linkedin.com/in/thomas-bernard-ceo/"}]}]}}}},"404":{"description":"No Mutual Connections signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No Mutual Connections signal with id c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/extraction":{"get":{"tags":["Signals"],"summary":"Get a Company Followers signal's extraction","description":"Know where a Company Followers signal stands: whether its followers have been priced, what the quote costs, whether the extraction is running and how many leads it has delivered. Poll it after requesting a quote or accepting one.\n\n**Why it matters:** a Company Followers signal in `icp` mode (the default — every follower matching your filters) produces **no leads until a quote is requested and accepted**, even while the signal is `active`. Its single-signal responses carry a `QUOTE_REQUIRED` warning until then.\n\n**Input:** the signal ID in the path.\n\n**Output:** `extraction` — the signal's latest extraction, or `null` when none was ever requested: `id`, `mode` (`icp` / `count`), `status` (`awaiting_quote` → `quoted` → `accepted` → `processing` → `results_ready` / `imported` → `settled`; or `declined`, `failed`), `estimatedFollowers` (followers matching your filters), `creditsQuoted` (the price), `creditsHeld`, `creditsCharged`, `creditsReleased`, `deliveredCount`, `error` (why a `failed` extraction stopped, e.g. `expired`, or `company_page_unavailable` when a company page does not exist), `createdAt`, `updatedAt`, and `expiresAt` (when an unaccepted quote lapses).\n\n**Errors:** `NOT_FOUND` (404, no such signal on your account), `UNSUPPORTED` (400, not a Company Followers signal).","operationId":"get_follower_extraction_api_v1_signals__signal_id__extraction_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"extraction":{"anyOf":[{"properties":{"id":{"type":"string","title":"Id","description":"Extraction id."},"mode":{"type":"string","enum":["icp","count"],"title":"Mode","description":"`icp`: every follower matching the signal's filters, priced by a quote you accept. `count`: a fixed number of followers, unfiltered, started at once."},"status":{"type":"string","title":"Status","description":"`awaiting_quote` (the quote is being computed — read this endpoint again in a minute), `quoted` (priced, waiting for your accept or decline), `accepted` (credits held, extraction starting), `processing` (extraction running), `results_ready` / `imported` (leads being delivered), `settled` (done: delivered leads charged, the rest of the hold returned), `declined` (you declined the quote), `failed` (see `error`)."},"requestedCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requestedcount","description":"`count` mode: the number of followers ordered. `null` in `icp` mode."},"estimatedFollowers":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimatedfollowers","description":"`icp` mode: followers of these pages matching your filters, as counted for the quote. `null` until the quote is ready."},"creditsQuoted":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Creditsquoted","description":"The price of the extraction: in `icp` mode 0.5 credit per matching follower, with a minimum of 75 credits; in `count` mode 1 credit per follower requested. `null` until the quote is ready."},"creditsHeld":{"type":"number","title":"Creditsheld","description":"Credits reserved on your balance for this extraction (from accept until it settles). Quoting holds nothing.","default":0},"creditsCharged":{"type":"number","title":"Creditscharged","description":"Credits actually charged — for the leads delivered, never above the hold.","default":0},"creditsReleased":{"type":"number","title":"Creditsreleased","description":"Credits of the hold returned to your balance (undelivered, declined, expired).","default":0},"deliveredCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deliveredcount","description":"Leads delivered so far by this extraction."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a `failed` extraction stopped: `expired` (the quote was not accepted within 30 days — request a new one), `insufficient_credits`, `cancelled` (the signal was paused before the extraction started), `companies_unavailable` (the company pages could not be read — try again later), `company_page_unavailable` (a page in `linkedinCompanyUrls` does not exist on LinkedIn — nothing was charged; replace it, then start a new extraction), `extraction_failed`. `null` otherwise."},"createdAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdat","description":"ISO-8601, UTC."},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updatedat","description":"ISO-8601, UTC."},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiresat","description":"`quoted` only: when the quote lapses if neither accepted nor declined (30 days after it was issued). It then turns `failed` with `error: expired` and nothing is charged."}},"type":"object","required":["id","mode","status"],"title":"ExtractionOrder","description":"One follower extraction of a Company Followers signal: its quote, its credits, its delivery.","examples":[{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}]},{"type":"null"}],"description":"The signal's extraction; `null` when none was ever requested."}},"type":"object","title":"ExtractionResponse","description":"The extraction of a Company Followers signal, or `null` when it has none.","examples":[{"extraction":{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}}]}}}},"404":{"description":"No signal with this id on your account","content":{"application/json":{"examples":{"NOT_FOUND":{"summary":"Unknown signal","value":{"detail":{"error":{"code":"NOT_FOUND","message":"Signal not found"}}}}}}}},"400":{"description":"Not a Company Followers signal","content":{"application/json":{"examples":{"UNSUPPORTED":{"summary":"Not a Company Followers signal","value":{"detail":{"error":{"code":"UNSUPPORTED","message":"Extraction is only available for follower signals"}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/extraction/accept":{"post":{"tags":["Signals"],"summary":"Accept a Company Followers extraction quote","description":"Accept the quote of a Company Followers signal and start the extraction: the matching followers are extracted, enriched and delivered as leads to your `webhookUrl` and connected destinations.\n\n**Input:** the signal ID in the path; no body. The signal must have a `quoted` extraction.\n\n**Output:** `extraction` with `status: accepted` (then `processing`, `results_ready`, `settled` — follow it with `GET .../extraction`) and `creditsHeld` equal to the quote.\n\n**Credits:** accepting **holds** the quoted credits on your balance. When the extraction settles you are charged for the leads actually delivered (never more than the hold) and the rest is returned (`creditsReleased`); if nothing is delivered, the whole hold is returned. Optional enrichments (emails, phones, ...) are charged per success at delivery, as on every signal. The price is re-checked at acceptance against the live follower count.\n\n**Errors:** `NO_QUOTE` (404, never quoted, declined, or the quote expired — request a new one), `NOT_QUOTED` (409, still `awaiting_quote`, or already accepted), `NO_PRICE` (409), `INSUFFICIENT_CREDITS` (402, balance below the quote — top up and accept again; the quote stays open), `EXTRACTION_FAILED` (502, the extraction could not start — the hold is returned, retry), `UNSUPPORTED` (400), `COMPANY_PAGE_UNAVAILABLE` (422, a `linkedinCompanyUrls` page does not exist on LinkedIn — `error.companyUrls` lists it; the quote is closed and nothing is held; replace it with PATCH /api/v1/signals/{signal_id}), `NOT_FOUND` (404).","operationId":"accept_follower_extraction_quote_api_v1_signals__signal_id__extraction_accept_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"extraction":{"anyOf":[{"properties":{"id":{"type":"string","title":"Id","description":"Extraction id."},"mode":{"type":"string","enum":["icp","count"],"title":"Mode","description":"`icp`: every follower matching the signal's filters, priced by a quote you accept. `count`: a fixed number of followers, unfiltered, started at once."},"status":{"type":"string","title":"Status","description":"`awaiting_quote` (the quote is being computed — read this endpoint again in a minute), `quoted` (priced, waiting for your accept or decline), `accepted` (credits held, extraction starting), `processing` (extraction running), `results_ready` / `imported` (leads being delivered), `settled` (done: delivered leads charged, the rest of the hold returned), `declined` (you declined the quote), `failed` (see `error`)."},"requestedCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requestedcount","description":"`count` mode: the number of followers ordered. `null` in `icp` mode."},"estimatedFollowers":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimatedfollowers","description":"`icp` mode: followers of these pages matching your filters, as counted for the quote. `null` until the quote is ready."},"creditsQuoted":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Creditsquoted","description":"The price of the extraction: in `icp` mode 0.5 credit per matching follower, with a minimum of 75 credits; in `count` mode 1 credit per follower requested. `null` until the quote is ready."},"creditsHeld":{"type":"number","title":"Creditsheld","description":"Credits reserved on your balance for this extraction (from accept until it settles). Quoting holds nothing.","default":0},"creditsCharged":{"type":"number","title":"Creditscharged","description":"Credits actually charged — for the leads delivered, never above the hold.","default":0},"creditsReleased":{"type":"number","title":"Creditsreleased","description":"Credits of the hold returned to your balance (undelivered, declined, expired).","default":0},"deliveredCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deliveredcount","description":"Leads delivered so far by this extraction."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a `failed` extraction stopped: `expired` (the quote was not accepted within 30 days — request a new one), `insufficient_credits`, `cancelled` (the signal was paused before the extraction started), `companies_unavailable` (the company pages could not be read — try again later), `company_page_unavailable` (a page in `linkedinCompanyUrls` does not exist on LinkedIn — nothing was charged; replace it, then start a new extraction), `extraction_failed`. `null` otherwise."},"createdAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdat","description":"ISO-8601, UTC."},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updatedat","description":"ISO-8601, UTC."},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiresat","description":"`quoted` only: when the quote lapses if neither accepted nor declined (30 days after it was issued). It then turns `failed` with `error: expired` and nothing is charged."}},"type":"object","required":["id","mode","status"],"title":"ExtractionOrder","description":"One follower extraction of a Company Followers signal: its quote, its credits, its delivery.","examples":[{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}]},{"type":"null"}],"description":"The signal's extraction; `null` when none was ever requested."}},"type":"object","title":"ExtractionResponse","description":"The extraction of a Company Followers signal, or `null` when it has none.","examples":[{"extraction":{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}}]}}}},"404":{"description":"No signal, or no quote to accept","content":{"application/json":{"examples":{"NOT_FOUND":{"summary":"Unknown signal","value":{"detail":{"error":{"code":"NOT_FOUND","message":"Signal not found"}}}},"NO_QUOTE":{"summary":"Never quoted, declined, or the quote expired","value":{"detail":{"error":{"code":"NO_QUOTE","message":"There is no quote to accept"}}}}}}}},"400":{"description":"Not a Company Followers signal","content":{"application/json":{"examples":{"UNSUPPORTED":{"summary":"Not a Company Followers signal","value":{"detail":{"error":{"code":"UNSUPPORTED","message":"Extraction is only available for follower signals"}}}}}}}},"422":{"description":"A company page of the signal does not exist on LinkedIn — nothing is held or charged","content":{"application/json":{"examples":{"COMPANY_PAGE_UNAVAILABLE":{"summary":"A page in `linkedinCompanyUrls` does not exist","value":{"detail":{"error":{"code":"COMPANY_PAGE_UNAVAILABLE","message":"This LinkedIn company page does not exist: https://www.linkedin.com/company/acme-unknown. Check the link (it must open the company's page on LinkedIn) and send the company's current URL, e.g. https://www.linkedin.com/company/lemlist."}}}}}}}},"402":{"description":"Balance below the quoted price","content":{"application/json":{"examples":{"INSUFFICIENT_CREDITS":{"summary":"Not enough credits","value":{"detail":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Not enough credits to accept this extraction"}}}}}}}},"409":{"description":"The quote is not ready yet","content":{"application/json":{"examples":{"NOT_QUOTED":{"summary":"Still being computed (`awaiting_quote`), or already accepted","value":{"detail":{"error":{"code":"NOT_QUOTED","message":"The quote is not ready yet"}}}},"NO_PRICE":{"summary":"The quote carries no price yet","value":{"detail":{"error":{"code":"NO_PRICE","message":"The quote has no price yet"}}}}}}}},"502":{"description":"The extraction could not be started — nothing is charged; retry","content":{"application/json":{"examples":{"EXTRACTION_FAILED":{"summary":"Start failed, hold returned","value":{"detail":{"error":{"code":"EXTRACTION_FAILED","message":"Could not confirm the extraction"}}}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/extraction/decline":{"post":{"tags":["Signals"],"summary":"Decline a Company Followers extraction quote","description":"Decline a Company Followers quote you do not want — for example after reading the price, before narrowing the filters and quoting again.\n\n**Input:** the signal ID in the path; no body. Works on a `quoted` or `awaiting_quote` extraction.\n\n**Output:** `extraction` with `status: declined`. Nothing is charged; any credits held are returned. The signal stays as it is (still `active`, still waiting for a quote — `QUOTE_REQUIRED`); request a new quote whenever you are ready.\n\n**Errors:** `NO_ORDER` (404, nothing open to decline), `NOT_DECLINABLE` (409, the quote was already accepted and the extraction is running — pause the signal to stop it), `UNSUPPORTED` (400), `NOT_FOUND` (404).","operationId":"decline_follower_extraction_quote_api_v1_signals__signal_id__extraction_decline_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"extraction":{"anyOf":[{"properties":{"id":{"type":"string","title":"Id","description":"Extraction id."},"mode":{"type":"string","enum":["icp","count"],"title":"Mode","description":"`icp`: every follower matching the signal's filters, priced by a quote you accept. `count`: a fixed number of followers, unfiltered, started at once."},"status":{"type":"string","title":"Status","description":"`awaiting_quote` (the quote is being computed — read this endpoint again in a minute), `quoted` (priced, waiting for your accept or decline), `accepted` (credits held, extraction starting), `processing` (extraction running), `results_ready` / `imported` (leads being delivered), `settled` (done: delivered leads charged, the rest of the hold returned), `declined` (you declined the quote), `failed` (see `error`)."},"requestedCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requestedcount","description":"`count` mode: the number of followers ordered. `null` in `icp` mode."},"estimatedFollowers":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimatedfollowers","description":"`icp` mode: followers of these pages matching your filters, as counted for the quote. `null` until the quote is ready."},"creditsQuoted":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Creditsquoted","description":"The price of the extraction: in `icp` mode 0.5 credit per matching follower, with a minimum of 75 credits; in `count` mode 1 credit per follower requested. `null` until the quote is ready."},"creditsHeld":{"type":"number","title":"Creditsheld","description":"Credits reserved on your balance for this extraction (from accept until it settles). Quoting holds nothing.","default":0},"creditsCharged":{"type":"number","title":"Creditscharged","description":"Credits actually charged — for the leads delivered, never above the hold.","default":0},"creditsReleased":{"type":"number","title":"Creditsreleased","description":"Credits of the hold returned to your balance (undelivered, declined, expired).","default":0},"deliveredCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deliveredcount","description":"Leads delivered so far by this extraction."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a `failed` extraction stopped: `expired` (the quote was not accepted within 30 days — request a new one), `insufficient_credits`, `cancelled` (the signal was paused before the extraction started), `companies_unavailable` (the company pages could not be read — try again later), `company_page_unavailable` (a page in `linkedinCompanyUrls` does not exist on LinkedIn — nothing was charged; replace it, then start a new extraction), `extraction_failed`. `null` otherwise."},"createdAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdat","description":"ISO-8601, UTC."},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updatedat","description":"ISO-8601, UTC."},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiresat","description":"`quoted` only: when the quote lapses if neither accepted nor declined (30 days after it was issued). It then turns `failed` with `error: expired` and nothing is charged."}},"type":"object","required":["id","mode","status"],"title":"ExtractionOrder","description":"One follower extraction of a Company Followers signal: its quote, its credits, its delivery.","examples":[{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}]},{"type":"null"}],"description":"The signal's extraction; `null` when none was ever requested."}},"type":"object","title":"ExtractionResponse","description":"The extraction of a Company Followers signal, or `null` when it has none.","examples":[{"extraction":{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}}]}}}},"404":{"description":"No signal, or nothing to decline","content":{"application/json":{"examples":{"NOT_FOUND":{"summary":"Unknown signal","value":{"detail":{"error":{"code":"NOT_FOUND","message":"Signal not found"}}}},"NO_ORDER":{"summary":"No open quote","value":{"detail":{"error":{"code":"NO_ORDER","message":"There is no extraction to decline"}}}}}}}},"400":{"description":"Not a Company Followers signal","content":{"application/json":{"examples":{"UNSUPPORTED":{"summary":"Not a Company Followers signal","value":{"detail":{"error":{"code":"UNSUPPORTED","message":"Extraction is only available for follower signals"}}}}}}}},"409":{"description":"The quote was already accepted","content":{"application/json":{"examples":{"NOT_DECLINABLE":{"summary":"The extraction is running","value":{"detail":{"error":{"code":"NOT_DECLINABLE","message":"This extraction has already been accepted and is running; it can no longer be declined. Pause the signal to stop it."}}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/extraction/extract":{"post":{"tags":["Signals"],"summary":"Start a fixed-count Company Followers extraction","description":"Start a fixed-size follower extraction on a Company Followers signal in `count` mode — the first `extractionLimit` followers of its pages, unfiltered, with no quote step. Activating a `count` signal already starts one; use this to run another once the previous one has finished.\n\n**Input:** the signal ID in the path; no body. Uses the signal's `linkedinCompanyUrls` and `extractionLimit`.\n\n**Output:** `extraction` with `mode: count`, `status: processing`, `requestedCount` and `creditsHeld` (1 credit per follower requested). At settlement you are charged for the leads delivered and the rest is returned.\n\n**Errors:** `WRONG_EXTRACTION_MODE` (400, the signal is in `icp` mode — use `.../extraction/quote`), `NO_COMPANIES` / `NO_COUNT` (400), `EXTRACTION_LIMIT_TOO_LOW` (422, `extractionLimit` is under the minimum of 100 — raise it with PATCH /api/v1/signals/{signal_id}; nothing is held or charged), `INSUFFICIENT_CREDITS` (402), `ALREADY_ACTIVE` (409), `EXTRACTION_FAILED` (502, nothing charged — retry), `COMPANY_PAGE_UNAVAILABLE` (422, a `linkedinCompanyUrls` page does not exist on LinkedIn — `error.companyUrls` lists it; nothing is held or charged; replace it with PATCH /api/v1/signals/{signal_id}), `UNSUPPORTED` (400), `NOT_FOUND` (404).","operationId":"start_follower_count_extraction_api_v1_signals__signal_id__extraction_extract_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"extraction":{"anyOf":[{"properties":{"id":{"type":"string","title":"Id","description":"Extraction id."},"mode":{"type":"string","enum":["icp","count"],"title":"Mode","description":"`icp`: every follower matching the signal's filters, priced by a quote you accept. `count`: a fixed number of followers, unfiltered, started at once."},"status":{"type":"string","title":"Status","description":"`awaiting_quote` (the quote is being computed — read this endpoint again in a minute), `quoted` (priced, waiting for your accept or decline), `accepted` (credits held, extraction starting), `processing` (extraction running), `results_ready` / `imported` (leads being delivered), `settled` (done: delivered leads charged, the rest of the hold returned), `declined` (you declined the quote), `failed` (see `error`)."},"requestedCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requestedcount","description":"`count` mode: the number of followers ordered. `null` in `icp` mode."},"estimatedFollowers":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimatedfollowers","description":"`icp` mode: followers of these pages matching your filters, as counted for the quote. `null` until the quote is ready."},"creditsQuoted":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Creditsquoted","description":"The price of the extraction: in `icp` mode 0.5 credit per matching follower, with a minimum of 75 credits; in `count` mode 1 credit per follower requested. `null` until the quote is ready."},"creditsHeld":{"type":"number","title":"Creditsheld","description":"Credits reserved on your balance for this extraction (from accept until it settles). Quoting holds nothing.","default":0},"creditsCharged":{"type":"number","title":"Creditscharged","description":"Credits actually charged — for the leads delivered, never above the hold.","default":0},"creditsReleased":{"type":"number","title":"Creditsreleased","description":"Credits of the hold returned to your balance (undelivered, declined, expired).","default":0},"deliveredCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deliveredcount","description":"Leads delivered so far by this extraction."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a `failed` extraction stopped: `expired` (the quote was not accepted within 30 days — request a new one), `insufficient_credits`, `cancelled` (the signal was paused before the extraction started), `companies_unavailable` (the company pages could not be read — try again later), `company_page_unavailable` (a page in `linkedinCompanyUrls` does not exist on LinkedIn — nothing was charged; replace it, then start a new extraction), `extraction_failed`. `null` otherwise."},"createdAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdat","description":"ISO-8601, UTC."},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updatedat","description":"ISO-8601, UTC."},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiresat","description":"`quoted` only: when the quote lapses if neither accepted nor declined (30 days after it was issued). It then turns `failed` with `error: expired` and nothing is charged."}},"type":"object","required":["id","mode","status"],"title":"ExtractionOrder","description":"One follower extraction of a Company Followers signal: its quote, its credits, its delivery.","examples":[{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}]},{"type":"null"}],"description":"The signal's extraction; `null` when none was ever requested."}},"type":"object","title":"ExtractionResponse","description":"The extraction of a Company Followers signal, or `null` when it has none.","examples":[{"extraction":{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}}]}}}},"404":{"description":"No signal with this id on your account","content":{"application/json":{"examples":{"NOT_FOUND":{"summary":"Unknown signal","value":{"detail":{"error":{"code":"NOT_FOUND","message":"Signal not found"}}}}}}}},"400":{"description":"The signal cannot be extracted as configured","content":{"application/json":{"examples":{"UNSUPPORTED":{"summary":"Not a Company Followers signal","value":{"detail":{"error":{"code":"UNSUPPORTED","message":"Extraction is only available for follower signals"}}}},"WRONG_EXTRACTION_MODE":{"summary":"The signal is in `icp` mode","value":{"detail":{"error":{"code":"WRONG_EXTRACTION_MODE","message":"This signal extracts the followers matching its filters (`extractionMode: icp`), which is priced by a quote first. Use POST /api/v1/signals/{signalId}/extraction/quote."}}}},"NO_COMPANIES":{"summary":"No company page to extract from","value":{"detail":{"error":{"code":"NO_COMPANIES","message":"Add at least one company to extract followers from"}}}},"NO_COUNT":{"summary":"No `extractionLimit`","value":{"detail":{"error":{"code":"NO_COUNT","message":"Set how many followers to extract"}}}}}}}},"422":{"description":"The extraction cannot be ordered as configured — nothing is held or charged","content":{"application/json":{"examples":{"COMPANY_PAGE_UNAVAILABLE":{"summary":"A page in `linkedinCompanyUrls` does not exist","value":{"detail":{"error":{"code":"COMPANY_PAGE_UNAVAILABLE","message":"This LinkedIn company page does not exist: https://www.linkedin.com/company/acme-unknown. Check the link (it must open the company's page on LinkedIn) and send the company's current URL, e.g. https://www.linkedin.com/company/lemlist."}}}},"EXTRACTION_LIMIT_TOO_LOW":{"summary":"`extractionLimit` is under the minimum of 100","value":{"detail":{"error":{"code":"EXTRACTION_LIMIT_TOO_LOW","message":"A follower count needs at least 100 profiles. Set extractionLimit to 100 or more."}}}}}}}},"402":{"description":"Balance below the extraction's price","content":{"application/json":{"examples":{"INSUFFICIENT_CREDITS":{"summary":"Not enough credits","value":{"detail":{"error":{"code":"INSUFFICIENT_CREDITS","message":"Not enough credits for this extraction"}}}}}}}},"409":{"description":"An extraction is already open on this signal","content":{"application/json":{"examples":{"ALREADY_ACTIVE":{"summary":"Already running","value":{"detail":{"error":{"code":"ALREADY_ACTIVE","message":"An extraction is already in progress"}}}}}}}},"502":{"description":"The extraction could not be started — nothing is charged; retry","content":{"application/json":{"examples":{"EXTRACTION_FAILED":{"summary":"Start failed, hold returned","value":{"detail":{"error":{"code":"EXTRACTION_FAILED","message":"Could not start the extraction"}}}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/extraction/quote":{"post":{"tags":["Signals"],"summary":"Request a quote for a Company Followers extraction","description":"Get the price of extracting every follower of your Company Followers pages who matches the signal's ICP filters — the step that turns an `icp` signal from `active`-but-silent into one that delivers leads. **Quoting is free and holds no credits**; nothing is extracted until you accept.\n\n**Input:** the signal ID in the path; no body. The quote is computed from the signal's stored config: `linkedinCompanyUrls` (required) and at least one ICP filter — `targetPersonas`, `customPersonaTitles`, `companySizeFilters`, `locations` or `targetCompanies`. To change what is quoted, `PATCH /api/v1/signals/{signal_id}` first, then quote again.\n\n**Output:** `extraction` (same shape as `GET .../extraction`). Usually `status: quoted` straight away, with `estimatedFollowers` and `creditsQuoted`. It can also come back `awaiting_quote`: the quote is still being computed — read `GET .../extraction` again after a few minutes.\n\n**Pricing:** 0.5 credit per matching follower, minimum 75 credits per extraction. A quote stays valid 30 days (`expiresAt`); unaccepted, it then turns `failed` with `error: expired` and you request a new one.\n\n**One step instead of three:** create or update the signal with `config.autoQuote: true` and a `config.maxCredits` budget, and the quote is requested — and accepted when it is within budget — for you as soon as the signal is `active`.\n\n**Errors:** `NO_COMPANIES` (400, no `linkedinCompanyUrls`), `NO_FILTER` (400, no ICP filter), `COMPANY_UNRESOLVED` (400, a `targetCompanies` URL could not be matched — the message lists them), `TOO_MANY_TITLES` / `FILTERS_TOO_LONG` (400, more targeting than one extraction can carry — the message says how much to remove), `WRONG_EXTRACTION_MODE` (400, the signal is in `count` mode — use `.../extraction/extract`), `UNSUPPORTED` (400, not a Company Followers signal), `INSUFFICIENT_CREDITS` (402, balance under the 75-credit minimum — top up first), `ALREADY_ACTIVE` (409, a quote or extraction is already open — accept or decline it first), `COMPANY_PAGE_UNAVAILABLE` (422, a `linkedinCompanyUrls` page does not exist on LinkedIn — `error.companyUrls` lists it; nothing is held or charged; replace it with PATCH /api/v1/signals/{signal_id}), `NOT_FOUND` (404).","operationId":"request_follower_extraction_quote_api_v1_signals__signal_id__extraction_quote_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"extraction":{"anyOf":[{"properties":{"id":{"type":"string","title":"Id","description":"Extraction id."},"mode":{"type":"string","enum":["icp","count"],"title":"Mode","description":"`icp`: every follower matching the signal's filters, priced by a quote you accept. `count`: a fixed number of followers, unfiltered, started at once."},"status":{"type":"string","title":"Status","description":"`awaiting_quote` (the quote is being computed — read this endpoint again in a minute), `quoted` (priced, waiting for your accept or decline), `accepted` (credits held, extraction starting), `processing` (extraction running), `results_ready` / `imported` (leads being delivered), `settled` (done: delivered leads charged, the rest of the hold returned), `declined` (you declined the quote), `failed` (see `error`)."},"requestedCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requestedcount","description":"`count` mode: the number of followers ordered. `null` in `icp` mode."},"estimatedFollowers":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimatedfollowers","description":"`icp` mode: followers of these pages matching your filters, as counted for the quote. `null` until the quote is ready."},"creditsQuoted":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Creditsquoted","description":"The price of the extraction: in `icp` mode 0.5 credit per matching follower, with a minimum of 75 credits; in `count` mode 1 credit per follower requested. `null` until the quote is ready."},"creditsHeld":{"type":"number","title":"Creditsheld","description":"Credits reserved on your balance for this extraction (from accept until it settles). Quoting holds nothing.","default":0},"creditsCharged":{"type":"number","title":"Creditscharged","description":"Credits actually charged — for the leads delivered, never above the hold.","default":0},"creditsReleased":{"type":"number","title":"Creditsreleased","description":"Credits of the hold returned to your balance (undelivered, declined, expired).","default":0},"deliveredCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Deliveredcount","description":"Leads delivered so far by this extraction."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a `failed` extraction stopped: `expired` (the quote was not accepted within 30 days — request a new one), `insufficient_credits`, `cancelled` (the signal was paused before the extraction started), `companies_unavailable` (the company pages could not be read — try again later), `company_page_unavailable` (a page in `linkedinCompanyUrls` does not exist on LinkedIn — nothing was charged; replace it, then start a new extraction), `extraction_failed`. `null` otherwise."},"createdAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdat","description":"ISO-8601, UTC."},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updatedat","description":"ISO-8601, UTC."},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiresat","description":"`quoted` only: when the quote lapses if neither accepted nor declined (30 days after it was issued). It then turns `failed` with `error: expired` and nothing is charged."}},"type":"object","required":["id","mode","status"],"title":"ExtractionOrder","description":"One follower extraction of a Company Followers signal: its quote, its credits, its delivery.","examples":[{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}]},{"type":"null"}],"description":"The signal's extraction; `null` when none was ever requested."}},"type":"object","title":"ExtractionResponse","description":"The extraction of a Company Followers signal, or `null` when it has none.","examples":[{"extraction":{"createdAt":"2026-10-09T09:15:00+00:00","creditsCharged":0.0,"creditsHeld":0.0,"creditsQuoted":620.0,"creditsReleased":0.0,"estimatedFollowers":1240,"expiresAt":"2026-11-08T09:15:00+00:00","id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","mode":"icp","status":"quoted","updatedAt":"2026-10-09T09:15:02+00:00"}}]}}}},"404":{"description":"No signal with this id on your account","content":{"application/json":{"examples":{"NOT_FOUND":{"summary":"Unknown signal","value":{"detail":{"error":{"code":"NOT_FOUND","message":"Signal not found"}}}}}}}},"400":{"description":"The signal cannot be quoted as configured","content":{"application/json":{"examples":{"UNSUPPORTED":{"summary":"Not a Company Followers signal","value":{"detail":{"error":{"code":"UNSUPPORTED","message":"Extraction is only available for follower signals"}}}},"WRONG_EXTRACTION_MODE":{"summary":"The signal is in `count` mode","value":{"detail":{"error":{"code":"WRONG_EXTRACTION_MODE","message":"This signal extracts a fixed number of followers (`extractionMode: count`), which needs no quote. Use POST /api/v1/signals/{signalId}/extraction/extract, or switch the signal to `extractionMode: \"icp\"`."}}}},"NO_COMPANIES":{"summary":"No company page to extract from","value":{"detail":{"error":{"code":"NO_COMPANIES","message":"Add at least one company to extract followers from"}}}},"NO_FILTER":{"summary":"No ICP filter set","value":{"detail":{"error":{"code":"NO_FILTER","message":"Add at least one persona, company size, location or company filter before requesting a quote"}}}},"COMPANY_UNRESOLVED":{"summary":"A `targetCompanies` entry could not be matched","value":{"detail":{"error":{"code":"COMPANY_UNRESOLVED","message":"These companies could not be matched on LinkedIn — remove them or pick them again from the search box: https://www.linkedin.com/company/acme-unknown"}}}},"TOO_MANY_TITLES":{"summary":"Too many job titles for one extraction","value":{"detail":{"error":{"code":"TOO_MANY_TITLES","message":"This extraction supports about 40 job titles at a time, and this signal has 55. Remove 15 and request the quote again."}}}},"FILTERS_TOO_LONG":{"summary":"Too many filters for one extraction","value":{"detail":{"error":{"code":"FILTERS_TOO_LONG","message":"This signal has more filters than one extraction can carry. Narrow the job titles, excluded titles or locations and request the quote again."}}}}}}}},"422":{"description":"A company page of the signal does not exist on LinkedIn — nothing is held or charged","content":{"application/json":{"examples":{"COMPANY_PAGE_UNAVAILABLE":{"summary":"A page in `linkedinCompanyUrls` does not exist","value":{"detail":{"error":{"code":"COMPANY_PAGE_UNAVAILABLE","message":"This LinkedIn company page does not exist: https://www.linkedin.com/company/acme-unknown. Check the link (it must open the company's page on LinkedIn) and send the company's current URL, e.g. https://www.linkedin.com/company/lemlist."}}}}}}}},"402":{"description":"Balance below the minimum price of an extraction","content":{"application/json":{"examples":{"INSUFFICIENT_CREDITS":{"summary":"Balance under 75 credits","value":{"detail":{"error":{"code":"INSUFFICIENT_CREDITS","message":"At least 75 credits are needed to accept an extraction quote. Top up before requesting one."}}}}}}}},"409":{"description":"An extraction is already open on this signal","content":{"application/json":{"examples":{"ALREADY_ACTIVE":{"summary":"A quote or extraction is already open","value":{"detail":{"error":{"code":"ALREADY_ACTIVE","message":"An extraction is already in progress"}}}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/funnel":{"get":{"tags":["Signals"],"summary":"Get a signal's rejection funnel","description":"See why a signal delivers fewer leads than you expect: how many people it found, how many each of your filters removed, and the job titles, company sizes, locations and industries it rejected most often. Built for tuning a signal (by hand or with an agent): pick the filter that removes the most candidates you would actually want, relax it with `PATCH /api/v1/signals/{signal_id}`, and read the funnel again a few days later.\n\n**Input:** the signal ID in the path; optional `days` (1-90, default 30), the window ending now.\n\n**Output:** `candidatesFound` (candidates found before any filter; `candidateUnit` says whether a candidate is a person or a job posting), `rejectedBy` (`persona`, `companySize`, `location`, `industry`, `excluded`, `duplicate`, `other`; job signals add `jobTitle`, `jobDescription` and `publishedDate`), `otherBreakdown` (splits `other`), `passedFilters`, `awaitingReview` (found, not yet checked), `unattributed` (checked, but the record does not say which of your settings removed them; left out of `rejectedBy` rather than guessed; `unattributedReason` explains it when the cause is known), `delivered` (leads delivered in the window) and `topRejected` (the five most frequent rejected values per filter; `unknown` means the value was missing, which usually means accepting unknown values is the lever).\n\n**How candidates are counted:** each candidate is counted once, under the FIRST filter it failed; `filterOrder` gives the order for this signal type (for competitor connections: company size, location, persona, industry, excluded companies, duplicates). A later filter never saw what an earlier one removed, so relaxing company size alone can move candidates on to the persona filter instead of into your leads. For social engagement and technology signals (`countingMethod: per_run_counters`) the counts are summed per collection run, so a person seen by several runs is counted each time, and no values are sampled.\n\n**Job signals** (job offers, republished job offers, recruitment campaigns): the filters judge job postings (`candidateUnit: job_posting`), then the people you target are searched at each company that passed, so `delivered` counts people and can exceed `passedFilters`.\n\n**Company followers:** the people each follower extraction returned, the role check and the company-size check they failed, and what was delivered. People already delivered on the signal are skipped without a per-person record, so they appear in `unattributed`.\n\n**Account watchlists:** `sources` holds one funnel per source (`countingMethod: per_source`); the top-level numbers add up the measured sources.\n\n**Coverage:** competitor connections, competitor customer care, job changes, new decision makers, employee departures, dormant LinkedIn posters, social engagement and technology signals, job offers, republished job offers, recruitment campaigns, company followers and account watchlists. Other signal types answer `supported: false` with a reason; that means 'not measured', never 'nothing was rejected'. Numbers are refreshed at most every 10 minutes.","operationId":"get_signal_funnel_api_v1_signals__signal_id__funnel_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"description":"Size of the window, in days, ending now. 1 to 90; default 30.","examples":[30],"default":30,"title":"Days"},"description":"Size of the window, in days, ending now. 1 to 90; default 30."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signalTypeId":{"type":"string","title":"Signaltypeid","description":"The signal's type."},"supported":{"type":"boolean","title":"Supported","description":"False when this signal type does not record per-filter rejections yet. Every count below is then absent: 'not measured', not zero."},"unsupportedReason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unsupportedreason","description":"Why the funnel is not available."},"countingMethod":{"anyOf":[{"type":"string","enum":["per_candidate","per_run_counters","per_source"]},{"type":"null"}],"title":"Countingmethod","description":"`per_candidate`: each candidate found is counted once, under the first filter it failed. `per_run_counters`: the counts are summed over every collection run in the window, so a person seen by several runs is counted each time, the stages can overlap slightly (they need not add up to `candidatesFound`), and no rejected values are sampled (`topRejected` is empty). `per_source` (account watchlists): the sum of `sources`, one entry per source of the watchlist."},"candidateUnit":{"anyOf":[{"type":"string","enum":["person","job_posting","mixed"]},{"type":"null"}],"title":"Candidateunit","description":"What one candidate is. `person` for most signals. `job_posting` for job signals: the filters judge postings, then people are searched at each company that passed, so `delivered` (people) can exceed `passedFilters` (postings). `mixed` for an account watchlist whose sources count different things: read `sources` for comparable numbers."},"filterOrder":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Filterorder","description":"The order this signal type applies its filters in, using the `rejectedBy` keys (`jobChangeAge` is the job-age part of `other`). Null for `per_run_counters`, whose stages are not strictly ordered."},"dataAvailableSince":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Dataavailablesince","description":"For `per_run_counters`: the date counting started. A window that begins earlier only covers the period since then."},"candidatesFound":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Candidatesfound","description":"People the signal found in the window, before any of your filters. A candidate that aged out before it was reviewed is not counted here, nor anywhere else in the funnel."},"rejectedBy":{"anyOf":[{"properties":{"persona":{"type":"integer","title":"Persona","description":"Removed because the person's role or job title does not match your target personas / custom job titles."},"companySize":{"type":"integer","title":"Companysize","description":"Removed because the company's headcount band is outside your company-size filters, or is unknown while unknown sizes are not accepted."},"location":{"type":"integer","title":"Location","description":"Removed because the person's location is outside your locations, or unknown."},"industry":{"type":"integer","title":"Industry","description":"Removed because the company's industry is outside your industry filters."},"excluded":{"type":"integer","title":"Excluded","description":"Removed because the company is on your excluded-companies list."},"duplicate":{"type":"integer","title":"Duplicate","description":"Already delivered to you on this signal (inside your deduplication window). Candidates refused by the final role check made just before delivery count under `persona`; before 2026-09-25 some of them were counted here instead."},"other":{"type":"integer","title":"Other","description":"Removed for any other reason. `otherBreakdown` splits this number."},"jobTitle":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Jobtitle","description":"Job-posting signals only (null otherwise): postings removed because the job title does not contain your included keywords, or contains an excluded one."},"jobDescription":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Jobdescription","description":"Job-posting signals only: postings removed on your job-description keywords (included or excluded)."},"publishedDate":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Publisheddate","description":"Job-posting signals only: postings removed because they were published before your `publishedDate` window."}},"type":"object","required":["persona","companySize","location","industry","excluded","duplicate","other"],"title":"FunnelRejectedBy","examples":[{"companySize":1157,"duplicate":1,"excluded":0,"industry":113,"location":226,"other":8,"persona":894}]},{"type":"null"}],"description":"How many candidates each filter removed. A candidate is counted under the FIRST filter it failed, in the order given by `filterOrder`. Filters later in that order never saw the candidates an earlier filter removed, so relaxing only an early filter can move them on to the next one."},"otherBreakdown":{"additionalProperties":{"type":"integer"},"type":"object","title":"Otherbreakdown","description":"Splits `rejectedBy.other`. Keys: `companyNotIdentified` (no company name, page or website to check your company filters against), `jobChangeTooOld` / `jobChangeDateUnknown` (job changes older than your maximum job age, or undated), `noWatchedCompany`, `noFormerCompany`, `notReactivated`, `sourceRemovedFromSettings`, `noLeadCreated`, `competitorEmployee` (the person works at the competitor you watch), `ownCompany` (the person works at your own company), `profileUnavailable` (the profile's details could not be read when it was reviewed), `noJobTitle` (the profile shows no job title or headline to check your personas against), `notMutual` (connected to only one of the two profiles of a mutual-connections signal), `existingNetwork` (already connected to the watched person when the signal started watching, and not part of your one-time extract: not delivered, not billed), `unclassified`."},"passedFilters":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Passedfilters","description":"Candidates that passed every filter. More than `delivered` when your daily lead limit or credit balance stopped a run."},"awaitingReview":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Awaitingreview","description":"Candidates found but not yet checked against your filters."},"unattributed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unattributed","description":"Candidates that were checked, but whose record does not say which of YOUR settings removed them. They are left out of `rejectedBy` rather than guessed."},"unattributedReason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unattributedreason","description":"Why `unattributed` is not zero, or why `candidatesFound` is empty, when this signal type has a known explanation."},"delivered":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Delivered","description":"Leads delivered by this signal in the window: the leads you can see. A lead removed by a final automatic check (e.g. a company-size recheck) is counted under that filter, not here."},"topRejected":{"anyOf":[{"properties":{"persona":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Persona","description":"Top rejected job titles."},"companySize":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Companysize","description":"Top rejected company-size bands."},"location":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Location","description":"Top rejected locations."},"industry":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Industry","description":"Top rejected industries."},"jobTitle":{"anyOf":[{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array"},{"type":"null"}],"title":"Jobtitle","description":"Job-posting signals only: top rejected job-posting titles."}},"type":"object","title":"FunnelTopRejected","examples":[{"companySize":[{"count":412,"value":"11-50"},{"count":208,"value":"1001-5000"}],"industry":[{"count":22,"value":"Software Development"}],"location":[{"count":31,"value":"London, England, United Kingdom"}],"persona":[{"count":10,"value":"Enterprise Account Executive"},{"count":7,"value":"Chief Executive Officer"}]}]},{"type":"null"}],"description":"The most frequent values among recently rejected candidates, per filter. Use them to choose what to relax: e.g. a job title rejected often that you would in fact want, or a size band just outside your filters."},"signalId":{"type":"string","title":"Signalid","description":"The signal's id."},"window":{"properties":{"days":{"type":"integer","title":"Days","description":"Length of the window, in days."},"from":{"type":"string","format":"date-time","title":"From","description":"Start of the window (UTC)."},"to":{"type":"string","format":"date-time","title":"To","description":"End of the window (UTC)."}},"type":"object","required":["days","from","to"],"title":"FunnelWindow","examples":[{"days":30,"from":"2026-08-26T09:00:00+00:00","to":"2026-09-25T09:00:00+00:00"}]},"sources":{"anyOf":[{"items":{"properties":{"signalTypeId":{"type":"string","title":"Signaltypeid","description":"The signal's type."},"supported":{"type":"boolean","title":"Supported","description":"False when this signal type does not record per-filter rejections yet. Every count below is then absent: 'not measured', not zero."},"unsupportedReason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unsupportedreason","description":"Why the funnel is not available."},"countingMethod":{"anyOf":[{"type":"string","enum":["per_candidate","per_run_counters","per_source"]},{"type":"null"}],"title":"Countingmethod","description":"`per_candidate`: each candidate found is counted once, under the first filter it failed. `per_run_counters`: the counts are summed over every collection run in the window, so a person seen by several runs is counted each time, the stages can overlap slightly (they need not add up to `candidatesFound`), and no rejected values are sampled (`topRejected` is empty). `per_source` (account watchlists): the sum of `sources`, one entry per source of the watchlist."},"candidateUnit":{"anyOf":[{"type":"string","enum":["person","job_posting","mixed"]},{"type":"null"}],"title":"Candidateunit","description":"What one candidate is. `person` for most signals. `job_posting` for job signals: the filters judge postings, then people are searched at each company that passed, so `delivered` (people) can exceed `passedFilters` (postings). `mixed` for an account watchlist whose sources count different things: read `sources` for comparable numbers."},"filterOrder":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Filterorder","description":"The order this signal type applies its filters in, using the `rejectedBy` keys (`jobChangeAge` is the job-age part of `other`). Null for `per_run_counters`, whose stages are not strictly ordered."},"dataAvailableSince":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Dataavailablesince","description":"For `per_run_counters`: the date counting started. A window that begins earlier only covers the period since then."},"candidatesFound":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Candidatesfound","description":"People the signal found in the window, before any of your filters. A candidate that aged out before it was reviewed is not counted here, nor anywhere else in the funnel."},"rejectedBy":{"anyOf":[{"properties":{"persona":{"type":"integer","title":"Persona","description":"Removed because the person's role or job title does not match your target personas / custom job titles."},"companySize":{"type":"integer","title":"Companysize","description":"Removed because the company's headcount band is outside your company-size filters, or is unknown while unknown sizes are not accepted."},"location":{"type":"integer","title":"Location","description":"Removed because the person's location is outside your locations, or unknown."},"industry":{"type":"integer","title":"Industry","description":"Removed because the company's industry is outside your industry filters."},"excluded":{"type":"integer","title":"Excluded","description":"Removed because the company is on your excluded-companies list."},"duplicate":{"type":"integer","title":"Duplicate","description":"Already delivered to you on this signal (inside your deduplication window). Candidates refused by the final role check made just before delivery count under `persona`; before 2026-09-25 some of them were counted here instead."},"other":{"type":"integer","title":"Other","description":"Removed for any other reason. `otherBreakdown` splits this number."},"jobTitle":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Jobtitle","description":"Job-posting signals only (null otherwise): postings removed because the job title does not contain your included keywords, or contains an excluded one."},"jobDescription":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Jobdescription","description":"Job-posting signals only: postings removed on your job-description keywords (included or excluded)."},"publishedDate":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Publisheddate","description":"Job-posting signals only: postings removed because they were published before your `publishedDate` window."}},"type":"object","required":["persona","companySize","location","industry","excluded","duplicate","other"],"title":"FunnelRejectedBy","examples":[{"companySize":1157,"duplicate":1,"excluded":0,"industry":113,"location":226,"other":8,"persona":894}]},{"type":"null"}],"description":"How many candidates each filter removed. A candidate is counted under the FIRST filter it failed, in the order given by `filterOrder`. Filters later in that order never saw the candidates an earlier filter removed, so relaxing only an early filter can move them on to the next one."},"otherBreakdown":{"additionalProperties":{"type":"integer"},"type":"object","title":"Otherbreakdown","description":"Splits `rejectedBy.other`. Keys: `companyNotIdentified` (no company name, page or website to check your company filters against), `jobChangeTooOld` / `jobChangeDateUnknown` (job changes older than your maximum job age, or undated), `noWatchedCompany`, `noFormerCompany`, `notReactivated`, `sourceRemovedFromSettings`, `noLeadCreated`, `competitorEmployee` (the person works at the competitor you watch), `ownCompany` (the person works at your own company), `profileUnavailable` (the profile's details could not be read when it was reviewed), `noJobTitle` (the profile shows no job title or headline to check your personas against), `notMutual` (connected to only one of the two profiles of a mutual-connections signal), `existingNetwork` (already connected to the watched person when the signal started watching, and not part of your one-time extract: not delivered, not billed), `unclassified`."},"passedFilters":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Passedfilters","description":"Candidates that passed every filter. More than `delivered` when your daily lead limit or credit balance stopped a run."},"awaitingReview":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Awaitingreview","description":"Candidates found but not yet checked against your filters."},"unattributed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unattributed","description":"Candidates that were checked, but whose record does not say which of YOUR settings removed them. They are left out of `rejectedBy` rather than guessed."},"unattributedReason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unattributedreason","description":"Why `unattributed` is not zero, or why `candidatesFound` is empty, when this signal type has a known explanation."},"delivered":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Delivered","description":"Leads delivered by this signal in the window: the leads you can see. A lead removed by a final automatic check (e.g. a company-size recheck) is counted under that filter, not here."},"topRejected":{"anyOf":[{"properties":{"persona":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Persona","description":"Top rejected job titles."},"companySize":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Companysize","description":"Top rejected company-size bands."},"location":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Location","description":"Top rejected locations."},"industry":{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array","title":"Industry","description":"Top rejected industries."},"jobTitle":{"anyOf":[{"items":{"properties":{"value":{"type":"string","title":"Value","description":"The observed value (a job title, a size band, a location or an industry). `unknown` means the value was missing."},"count":{"type":"integer","title":"Count","description":"Rejected candidates with this value, among those sampled."}},"type":"object","required":["value","count"],"title":"FunnelSample","examples":[{"count":10,"value":"Enterprise Account Executive"}]},"type":"array"},{"type":"null"}],"title":"Jobtitle","description":"Job-posting signals only: top rejected job-posting titles."}},"type":"object","title":"FunnelTopRejected","examples":[{"companySize":[{"count":412,"value":"11-50"},{"count":208,"value":"1001-5000"}],"industry":[{"count":22,"value":"Software Development"}],"location":[{"count":31,"value":"London, England, United Kingdom"}],"persona":[{"count":10,"value":"Enterprise Account Executive"},{"count":7,"value":"Chief Executive Officer"}]}]},{"type":"null"}],"description":"The most frequent values among recently rejected candidates, per filter. Use them to choose what to relax: e.g. a job title rejected often that you would in fact want, or a size band just outside your filters."},"source":{"type":"string","title":"Source","description":"The watchlist source, as named in the signal's `sources` settings (e.g. `fundraising`, `job_offers`, `new_decision_makers`, `competitor_connections`)."}},"type":"object","required":["signalTypeId","supported","source"],"title":"FunnelSource","description":"One source of an account watchlist.","examples":[{"delivered":4,"signalTypeId":"job_offers_watchlist","source":"job_offers","supported":false,"unsupportedReason":"This signal type does not record per-filter rejections yet. Counts will appear here once it does; until then, a missing funnel means 'not measured', not 'nothing was rejected'."}]},"type":"array"},{"type":"null"}],"title":"Sources","description":"Account watchlists only: one funnel per source, each counted the way that source's signal type counts. The top-level numbers add up the sources that are measured; `delivered` adds up all of them."},"countedAt":{"type":"string","format":"date-time","title":"Countedat","description":"When these numbers were computed. They can be up to an hour old."}},"type":"object","required":["signalTypeId","supported","signalId","window","countedAt"],"title":"SignalFunnelResponse","examples":[{"awaitingReview":0,"candidateUnit":"person","candidatesFound":2399,"countedAt":"2026-09-25T09:00:00+00:00","countingMethod":"per_candidate","delivered":0,"filterOrder":["companySize","location","persona","industry","excluded","duplicate"],"otherBreakdown":{"companyNotIdentified":8},"passedFilters":0,"rejectedBy":{"companySize":1157,"duplicate":1,"excluded":0,"industry":113,"location":226,"other":8,"persona":894},"signalId":"b92cde5c-7381-4d85-9c9b-3287301d053d","signalTypeId":"competitor_relationship_monitoring","supported":true,"topRejected":{"companySize":[{"count":412,"value":"11-50"},{"count":208,"value":"1001-5000"},{"count":95,"value":"unknown"}],"industry":[{"count":22,"value":"Software Development"}],"location":[{"count":31,"value":"London, England, United Kingdom"}],"persona":[{"count":10,"value":"Enterprise Account Executive"},{"count":7,"value":"Chief Executive Officer"},{"count":6,"value":"Board Member"}]},"unattributed":0,"window":{"days":30,"from":"2026-08-26T09:00:00+00:00","to":"2026-09-25T09:00:00+00:00"}}]}}}},"404":{"description":"No signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"Signal not found"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/leads":{"get":{"tags":["Signals"],"summary":"List a signal's leads","description":"Read the leads a signal has delivered — the prospects and companies it found, with their enriched contact and company details — without running a webhook receiver. Use it to review what a signal produced yesterday, to back-fill a CRM after an outage, or to let an AI assistant answer \"show me my new leads\".\n\n**Input:** `signalId` in the path; optional `since` (ISO-8601 timestamp: only leads produced at or after it), `limit` (1-100, default 25) and `offset` (default 0) to page through the results.\n\n**Output:** `signalId`, `total` (matching leads across all pages), `limit`, `offset`, `hasMore`, and `leads` — newest first, each in exactly the shape the signal's webhook delivers (nested `signal` / `contact` / `company`, snake_case, see `outputFields` in `GET /api/v1/signal-types`). For an Account Watchlist, the leads of every enabled source are returned under the watchlist's own id.\n\nReading leads is free: a lead is charged once, when it is produced. Leads that did not pass your filters, and watchlist changes still waiting for your review, are not returned.","operationId":"list_signal_leads_api_v1_signals__signal_id__leads_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only leads produced at or after this ISO-8601 timestamp.","examples":["2026-10-07T00:00:00+00:00"],"title":"Since"},"description":"Only leads produced at or after this ISO-8601 timestamp."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Leads per page, 1 to 100; default 25.","default":25,"title":"Limit"},"description":"Leads per page, 1 to 100; default 25."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Leads to skip (pagination).","default":0,"title":"Offset"},"description":"Leads to skip (pagination)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signalId":{"type":"string","title":"Signalid","description":"The signal's id."},"total":{"type":"integer","title":"Total","description":"Leads matching the request, across all pages."},"limit":{"type":"integer","title":"Limit","description":"Page size used for this response."},"offset":{"type":"integer","title":"Offset","description":"Leads skipped before this page."},"hasMore":{"type":"boolean","title":"Hasmore","description":"True when another page follows."},"leads":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Leads","description":"The leads, newest first. Each one is the exact object the signal's webhook delivers: nested `signal`, `contact` and `company` objects with snake_case fields (`contact` is null for signals that deliver companies only). The fields per signal type are listed in `outputFields` of `GET /api/v1/signal-types`."}},"type":"object","required":["signalId","total","limit","offset","hasMore","leads"],"title":"SignalLeadsResponse","description":"A page of the leads a signal has delivered, newest first.","examples":[{"hasMore":true,"leads":[{"company":{"hq_city":"Paris","hq_country_code":"FR","industry":"Software Development","linkedin_url":"https://www.linkedin.com/company/doctolib","location":"Paris, France","name":"Doctolib","website":"https://doctolib.fr"},"contact":{"city":"Paris","country_code":"FR","created_at":"2026-10-07T09:12:00+00:00","email":"marie.dupont@doctolib.fr","first_name":"Marie","last_name":"Dupont","lead_id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","linkedin_profile_url":"https://www.linkedin.com/in/marie-dupont","location":"Paris, France","matched_persona":"Sales Director","phone":"","sales_navigator_profile_url":"","title":"VP Sales"},"signal":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","last_signal":"Job Changes","last_signal_date":"2026-10-07","name":"New sales leaders in French SaaS","tracked_company":"","type":"job_changes"}}],"limit":25,"offset":0,"signalId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","total":42}]}}}},"404":{"description":"No signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"Signal not found"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/replay-webhook":{"post":{"tags":["Signals"],"summary":"Replay a signal's leads to its webhook","description":"Resend every lead already produced by this signal to its configured `webhookUrl` — use it after fixing an endpoint that was down or rejecting deliveries. **Input:** `signalId` in the path; no body. **Output:** `total` leads considered, `sent`, `failed`, a human-readable `message`, and a `warning` when the deliveries went out unsigned because no API key is linked to the signal.","operationId":"public_replay_webhook_api_v1_signals__signal_id__replay_webhook_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"success":{"type":"boolean","title":"Success","description":"True when the replay ran"},"total":{"type":"integer","title":"Total","description":"Leads considered for replay"},"sent":{"type":"integer","title":"Sent","description":"Leads delivered successfully"},"failed":{"type":"integer","title":"Failed","description":"Leads whose delivery failed"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Human-readable summary"},"warning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Warning","description":"Something to fix even though the replay ran, e.g. deliveries sent unsigned because no API key is linked to the signal"}},"type":"object","required":["success","total","sent","failed"],"title":"ReplayWebhookResponse","description":"Result of replaying a signal's existing leads to its webhook.","examples":[{"failed":0,"message":"ok","sent":42,"success":true,"total":42}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}/test-webhook":{"post":{"tags":["Signals"],"summary":"Send a test payload to a signal's webhook","description":"Deliver a sample lead to the signal's configured `webhookUrl` so you can verify your endpoint before real leads arrive. **Input:** `signalId` in the path; optional body `{\"url\": \"...\"}` to test another endpoint than the saved `webhookUrl` (for example before saving it). The URL must be HTTP(S) and reachable from the internet. **Output:** `success`, the `statusCode` your endpoint returned, the exact `payloadSent` (it carries `is_test: true` so you can discard it), and the first bytes of your `responseBody`. `signed` tells whether the request carried the `X-Webhook-Signature` / `X-Webhook-Timestamp` headers: when no API key is linked to the signal the test is sent unsigned, like real deliveries, and `warning` says so. On a transport failure `success` is false and `error` explains why.","operationId":"public_test_webhook_api_v1_signals__signal_id__test_webhook_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"properties":{"url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Url","description":"Endpoint to test instead of the signal's saved webhook URL"}},"type":"object","title":"TestWebhookRequest","description":"Optional body for the webhook test.\n\nWithout it the test goes to the URL saved on the signal. With `url`, it goes\nto that URL instead — so an endpoint can be checked before it is saved.","examples":[{"url":"https://hooks.example.com/rodz/leads"}]},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"success":{"type":"boolean","title":"Success","description":"True when your endpoint answered with a 2xx/3xx"},"statusCode":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Statuscode","description":"HTTP status your endpoint returned"},"payloadSent":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Payloadsent","description":"The exact test payload delivered, carrying `is_test: true`"},"responseBody":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Responsebody","description":"First bytes of your endpoint's response"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why the send failed; absent on success"},"signed":{"type":"boolean","title":"Signed","description":"True when the request carried the X-Webhook-Signature and X-Webhook-Timestamp headers. False when no API key is linked to the signal: the test (like real deliveries) is then sent unsigned.","default":true},"warning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Warning","description":"Something to fix even though the send worked, e.g. an unsigned delivery"}},"type":"object","required":["success"],"title":"TestWebhookResponse","description":"Result of sending a test payload to a signal's configured webhook.\n\nExposed in the public OpenAPI document 2026-08-07: `info.description` had\nadvertised this endpoint and `/replay-webhook` under \"Testing & Management\"\nwhile the whole signal_routes router was registered with\ninclude_in_schema=False, so neither appeared in `paths` and no client could\nbe generated for them — reported by a customer generating a Java client.\nBoth accept a customer API key (verify_api_key_or_session), so they were\ncallable but undocumentable.","examples":[{"payloadSent":{"contact":"","signal":{"type":"fundraising"}},"responseBody":"ok","signed":true,"statusCode":200,"success":true}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/account/credits":{"get":{"tags":["Account Management"],"summary":"Get credit balance","description":"Check your remaining lead-detection credits to determine if you can activate new signals or need to purchase additional credit packs.\n\n**Input:** None (authenticated via API key; no request body or query parameters)\n\n**Output:** Your current credit balance (`credits`, floating-point number representing available lead-gen budget) and registered company name (`companyName`, string or null).","operationId":"get_credits_api_v1_account_credits_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"credits":{"type":"number","title":"Credits"},"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"}},"type":"object","required":["credits"],"title":"CreditsResponse","description":"Credits balance response."}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/account/credits/usage":{"get":{"tags":["Account Management"],"summary":"Get API usage & credit consumption","description":"See exactly which API calls are consuming your credits, so you can pinpoint the integration or workflow that's spending the most and dial it back.\n\n**Input:** `from`/`to` (ISO-8601 timestamps; default is the last 7 days), an optional `endpoint` to filter to a single route (e.g. `/v4/firmographic`), `interval` (`hour` or `day`, default `hour`) controlling the time-series bucket size, and `limit`/`offset` (default 100 / 0) to page through the individual-call log.\n\n**Output:** `totalCalls` and `totalCredits` for the window; `byEndpoint` — a per-route rollup sorted by spend, so you can see which route costs the most; `timeSeries` — calls and credits per hour or day, to spot exactly when a spike began; and `calls` — a paginated log of individual billed calls (timestamp, route, credits) for a precise per-call, per-time-range, per-route view.","operationId":"get_api_usage_api_v1_account_credits_usage_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Window start (ISO-8601). Defaults to 7 days ago.","title":"From"},"description":"Window start (ISO-8601). Defaults to 7 days ago."},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Window end (ISO-8601). Defaults to now.","title":"To"},"description":"Window end (ISO-8601). Defaults to now."},{"name":"endpoint","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter to a single route, e.g. /v4/firmographic.","title":"Endpoint"},"description":"Filter to a single route, e.g. /v4/firmographic."},{"name":"interval","in":"query","required":false,"schema":{"type":"string","pattern":"^(hour|day)$","description":"Time-series bucket size: hour or day.","default":"hour","title":"Interval"},"description":"Time-series bucket size: hour or day."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Max individual calls to return (pagination).","default":100,"title":"Limit"},"description":"Max individual calls to return (pagination)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Offset into the individual-call log.","default":0,"title":"Offset"},"description":"Offset into the individual-call log."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"fromDate":{"type":"string","format":"date-time","title":"Fromdate","description":"Start of the window (UTC)."},"toDate":{"type":"string","format":"date-time","title":"Todate","description":"End of the window (UTC)."},"totalCalls":{"type":"integer","title":"Totalcalls","description":"Total billed calls in the window (after any route filter)."},"totalCredits":{"type":"number","title":"Totalcredits","description":"Total credits consumed in the window (after any route filter)."},"byEndpoint":{"items":{"properties":{"endpoint":{"type":"string","title":"Endpoint","description":"The API route that was called.","examples":["/v4/firmographic"]},"calls":{"type":"integer","title":"Calls","description":"Number of billed calls to this route in the window.","examples":[2414]},"credits":{"type":"number","title":"Credits","description":"Credits consumed by this route in the window.","examples":[1207.0]}},"type":"object","required":["endpoint","calls","credits"],"title":"ApiUsageByEndpoint","description":"Per-route rollup of billable API calls.","examples":[{"calls":2414,"credits":1207.0,"endpoint":"/v4/firmographic"}]},"type":"array","title":"Byendpoint","description":"Per-route rollup, highest spend first."},"timeSeries":{"items":{"properties":{"bucket":{"type":"string","format":"date-time","title":"Bucket","description":"Start of the time bucket (UTC).","examples":["2026-07-23T16:00:00+00:00"]},"calls":{"type":"integer","title":"Calls","description":"Billed calls in this bucket.","examples":[1031]},"credits":{"type":"number","title":"Credits","description":"Credits consumed in this bucket.","examples":[515.5]}},"type":"object","required":["bucket","calls","credits"],"title":"ApiUsageBucket","description":"Billable API usage aggregated into one time bucket.","examples":[{"bucket":"2026-07-23T16:00:00+00:00","calls":1031,"credits":515.5}]},"type":"array","title":"Timeseries","description":"Usage per time bucket (hour or day), oldest first."},"calls":{"items":{"properties":{"timestamp":{"type":"string","format":"date-time","title":"Timestamp","description":"When the call was billed (UTC).","examples":["2026-07-23T16:42:07+00:00"]},"endpoint":{"type":"string","title":"Endpoint","description":"The API route that was called.","examples":["/v4/contact"]},"credits":{"type":"number","title":"Credits","description":"Credits charged for this call.","examples":[0.5]}},"type":"object","required":["timestamp","endpoint","credits"],"title":"ApiUsageCall","description":"A single billed API call.","examples":[{"credits":0.5,"endpoint":"/v4/contact","timestamp":"2026-07-23T16:42:07+00:00"}]},"type":"array","title":"Calls","description":"Individual billed calls, newest first (paginated via limit/offset)."},"hasMore":{"type":"boolean","title":"Hasmore","description":"True if more calls exist beyond this page.","default":false}},"type":"object","required":["fromDate","toDate","totalCalls","totalCredits"],"title":"ApiUsageResponse","description":"Billable API-call usage for your account over a time window.","examples":[{"byEndpoint":[{"calls":2414,"credits":1207.0,"endpoint":"/v4/firmographic"},{"calls":1242,"credits":621.0,"endpoint":"/v4/contact"},{"calls":100,"credits":100.0,"endpoint":"/people-search"}],"calls":[{"credits":0.5,"endpoint":"/v4/contact","timestamp":"2026-07-23T16:42:07+00:00"}],"fromDate":"2026-07-16T00:00:00+00:00","hasMore":true,"timeSeries":[{"bucket":"2026-07-23T16:00:00+00:00","calls":1031,"credits":515.5},{"bucket":"2026-07-23T17:00:00+00:00","calls":1051,"credits":525.5}],"toDate":"2026-07-23T20:00:00+00:00","totalCalls":3756,"totalCredits":1928.0}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"from","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/integrations":{"get":{"tags":["Account Management"],"summary":"List your connected integrations","description":"See which lead-push integrations are connected on your account and how each connects.\n\n**Input:** none (just your API key).\n\n**Output:** one entry per provider with `connected`, `label`, and `connectVia` (`api` = connect with a key via `PUT /api/v1/integrations/{provider}`; `dashboard` = connect once via OAuth in the dashboard). Use the `provider` id in a signal's `destinations`. Keys are never returned.","operationId":"list_integrations_api_v1_integrations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicIntegrationsResponse"}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/integrations/{provider}":{"put":{"tags":["Account Management"],"summary":"Connect an API-key integration","description":"Connect (or re-key) an API-key integration so signals can push leads to it. The key is validated with the provider before it's stored, and encrypted at rest.\n\n**Input:** `apiKey` (required), optional `label`; Gong also takes `secret` + `baseUrl`.\n\n**Output:** the provider's connection status.\n\n**Providers:** instantly, lemlist, smartlead, emelia, lagrowthmachine, gong, claap. OAuth providers (hubspot, pipedrive, google_sheets, slack) return `400 USE_DASHBOARD_OAUTH` — connect them once in the dashboard, then select them per signal via `destinations`.","operationId":"connect_integration_api_v1_integrations__provider__put","security":[{"BearerAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicIntegrationConnect"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicIntegrationStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"provider","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}},"delete":{"tags":["Account Management"],"summary":"Disconnect an integration","description":"Remove a connected integration. Signals routing to it stop pushing there.","operationId":"disconnect_integration_api_v1_integrations__provider__delete","security":[{"BearerAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"provider","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/integrations/{provider}/campaigns":{"get":{"tags":["Account Management"],"summary":"List an integration's push targets","description":"List the selectable push targets for a connected integration so you can pick the id to route a signal to.\n\n**Input:** the `provider` (instantly, lemlist, smartlead, emelia, lagrowthmachine, gong).\n\n**Output:** `items[]` of `{id, name, status}`. Use `id` as `campaignId` for email tools or `flowId` for Gong; for LaGrowthMachine use `name` as `audienceName`. HubSpot / Pipedrive / Google Sheets have no target list (they're enabled or URL-based).\n\nReturns `409` if the provider isn't connected.","operationId":"list_integration_campaigns_api_v1_integrations__provider__campaigns_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCampaignsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"provider","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/personas":{"get":{"tags":["Account Management"],"summary":"List available personas","description":"Discover the job titles and role names that Rodz recognizes across departments and seniority levels — so you can target the exact personas you want in your signals (e.g., Sales Directors, CTOs, HR Managers).\n\n**Input:** Your API key (in Authorization header; no request body fields).\n\n**Output:** All available personas grouped by department (Sales, Marketing, Tech, Finance, etc.) and seniority tier (director/CxO, manager, individual contributor). For each persona: the English `name` (e.g., \"CEO\", \"Sales Director\") to use in the `targetPersonas` field of signal creation requests, the French equivalent, and the underlying job title variants matched for that persona in both languages.","operationId":"list_personas_api_v1_personas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"departments":{"items":{"properties":{"department":{"type":"string","title":"Department","description":"Department name","examples":["Sales & BD"]},"personas":{"properties":{"director":{"items":{"properties":{"name":{"type":"string","title":"Name","description":"English name (use this value in targetPersonas)","examples":["CEO"]},"nameFr":{"type":"string","title":"Namefr","description":"French name","examples":["Directeur Général"]},"jobTitlesEn":{"items":{"type":"string"},"type":"array","title":"Jobtitlesen","description":"English job title variants covered by this persona"},"jobTitlesFr":{"items":{"type":"string"},"type":"array","title":"Jobtitlesfr","description":"French job title variants covered by this persona"}},"type":"object","required":["name","nameFr"],"title":"PersonaName","description":"A persona that can be used in targetPersonas."},"type":"array","title":"Director","description":"Director / CxO level"},"manager":{"items":{"properties":{"name":{"type":"string","title":"Name","description":"English name (use this value in targetPersonas)","examples":["CEO"]},"nameFr":{"type":"string","title":"Namefr","description":"French name","examples":["Directeur Général"]},"jobTitlesEn":{"items":{"type":"string"},"type":"array","title":"Jobtitlesen","description":"English job title variants covered by this persona"},"jobTitlesFr":{"items":{"type":"string"},"type":"array","title":"Jobtitlesfr","description":"French job title variants covered by this persona"}},"type":"object","required":["name","nameFr"],"title":"PersonaName","description":"A persona that can be used in targetPersonas."},"type":"array","title":"Manager","description":"Manager level"},"employee":{"items":{"properties":{"name":{"type":"string","title":"Name","description":"English name (use this value in targetPersonas)","examples":["CEO"]},"nameFr":{"type":"string","title":"Namefr","description":"French name","examples":["Directeur Général"]},"jobTitlesEn":{"items":{"type":"string"},"type":"array","title":"Jobtitlesen","description":"English job title variants covered by this persona"},"jobTitlesFr":{"items":{"type":"string"},"type":"array","title":"Jobtitlesfr","description":"French job title variants covered by this persona"}},"type":"object","required":["name","nameFr"],"title":"PersonaName","description":"A persona that can be used in targetPersonas."},"type":"array","title":"Employee","description":"Employee / Individual contributor level"}},"type":"object","title":"PersonasByTier","description":"Personas grouped by seniority tier."}},"type":"object","required":["department","personas"],"title":"PersonaDepartment","description":"A department with its personas."},"type":"array","title":"Departments"}},"type":"object","required":["departments"],"title":"PersonaListResponse","description":"Response listing all available personas.","example":{"departments":[{"department":"Sales & BD","personas":{"director":[{"name":"Sales Director","nameFr":"Directeur Commercial"},{"name":"Business Unit Director","nameFr":"Directeur Business Unit"}],"employee":[{"name":"Account Executive","nameFr":"Chargé de Compte"},{"name":"SDR / BDR","nameFr":"SDR / BDR"},{"name":"Business Developer","nameFr":"Business Developer"}],"manager":[{"name":"Sales Manager","nameFr":"Responsable Commercial"},{"name":"Account Manager","nameFr":"Responsable de Comptes"}]}},{"department":"Marketing","personas":{"director":[{"name":"Marketing Director","nameFr":"Directeur Marketing"},{"name":"Communication Director","nameFr":"Directeur Communication"}],"employee":[{"name":"Community Manager","nameFr":"Community Manager"},{"name":"Copywriter","nameFr":"Rédacteur"}],"manager":[{"name":"Marketing Manager","nameFr":"Responsable Marketing"},{"name":"Content Manager","nameFr":"Responsable Contenu"}]}}]}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signal-types":{"get":{"tags":["Account Management"],"summary":"List the signal library (catalog) — START HERE","description":"**The entry point for building a Rodz integration.** Browse the full catalog of signal types you can create — the whole Rodz signal engine in one call, generated from the same models the API validates against, so it cannot drift from what actually works on the wire. A full integration is: call this once to pick a signal type -> `POST createEndpoint` with a body built from `configParameters` to create it -> receive leads on your `webhookUrl` shaped like `outputFields` -> `POST /api/v1/signals/{signalId}/test-webhook` to fire a synthetic test event, or `.../replay-webhook` to resend a real past one, while you build your receiver.\n\n**Input:** none (just your API key).\n\n**Output:** an array of signal types. Each entry gives, per type: `kind` (an open-ended `signal` or a `watchlist` narrowed to a list you supply), a use-case description, `configParameters` — the CLOSED set of request fields `createEndpoint` accepts (see `unknownParameters` for what happens to anything else), `pricingModel` — credits only, never euros, since you set your own price per credit for your customers — `outputFields` — the exact webhook payload shape — and `relatedSignalTypes` for the signal types it is easy to confuse this one with (a narrower watchlist sibling, the `account_watchlist` umbrella, or a similar-looking signal with different targeting). Use `createEndpoint` + `configParameters` to build the `POST /api/v1/signals/...` request, and `outputFields` to know what each delivered lead contains.","operationId":"list_signal_types_catalog_api_v1_signal_types_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signalTypes":{"items":{"properties":{"signalTypeId":{"type":"string","title":"Signaltypeid","description":"Stable identifier for the signal type."},"name":{"type":"string","title":"Name","description":"Human-readable name."},"description":{"type":"string","title":"Description","description":"What this signal detects and delivers."},"category":{"type":"string","title":"Category","description":"Grouping category."},"kind":{"type":"string","title":"Kind","description":"`\"signal\"` (an open-ended search) or `\"watchlist\"` (narrowed to a list of companies or people you supply via the watchlist membership endpoints, `GET|POST|DELETE /api/v1/watchlists/{signalId}/{companies,profiles}`)."},"creditsPerLead":{"type":"number","title":"Creditsperlead","description":"Credits charged per qualified lead."},"createEndpoint":{"type":"string","title":"Createendpoint","description":"POST here (with your config) to create this signal. Always use this value rather than deriving a path from `signalTypeId` — several slugs deliberately differ from the type id (for example `company_post_reactions` is created at `/api/v1/signals/company-page-engagement`)."},"deprecatedCreateEndpoints":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Deprecatedcreateendpoints","description":"Older create paths for this same signal, from a past rename. Each still accepts the identical request body and delivers the identical webhook, and is kept working indefinitely — but is no longer advertised in OpenAPI as the primary path. Build new integrations against `createEndpoint`; this is only for recognising a path you may already be calling."},"configParameters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Configparameters","description":"Map of the configurable `config.*` fields this signal's create endpoint accepts, keyed by the exact camelCase request field name (e.g. `companySizeFilters`, `getEmails`), each with its type, description, and allowed values / default. Copy these keys straight into your POST body. This map is CLOSED — see `unknownParameters` for what happens to a key not listed here."},"unknownParameters":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unknownparameters","description":"What happens to a `config` key that is not one of `configParameters`' keys — either silently ignored (accepted, no effect) or rejected with a 422. There is no third option: a key you invent never changes behaviour."},"outputFields":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Outputfields","description":"Dotted paths of the fields delivered on each webhook lead, in the payload's nested snake_case shape (e.g. `contact.first_name`, `company.linkedin_url`, `signal.tracked_company`)."},"useCases":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Usecases","description":"Concrete example workflows this signal's leads enable — what to build with the data."},"pricingModel":{"anyOf":[{"properties":{"unit":{"type":"string","title":"Unit","description":"The billable unit. `\"per_lead_delivered\"` for every signal type except `job_change_watchlist`, which bills `\"per_profile_per_poll\"` — see `note`."},"baseCredits":{"type":"number","title":"Basecredits","description":"Credits charged per billable unit, before any add-on."},"addOns":{"anyOf":[{"items":{"properties":{"parameter":{"type":"string","title":"Parameter","description":"The `configParameters` key that turns this add-on on."},"creditsOnSuccess":{"type":"number","title":"Creditsonsuccess","description":"Credits charged, only when the enrichment succeeds — never on a miss."},"description":{"type":"string","title":"Description","description":"What the add-on does."}},"type":"object","required":["parameter","creditsOnSuccess","description"],"title":"PricingAddOn","description":"An optional paid enrichment this signal's `configParameters` can turn on.","examples":[{"creditsOnSuccess":0.5,"description":"Finds a professional email address for the contact. Charged once per lead, only on success.","parameter":"getEmails"}]},"type":"array"},{"type":"null"}],"title":"Addons","description":"Optional paid enrichments this signal's `configParameters` can turn on, each charged only on success, on top of `baseCredits`."},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note","description":"Set only when the billing unit needs explaining beyond its name."}},"type":"object","required":["unit","baseCredits"],"title":"PricingModel","description":"How this signal is billed: credits only — no euro prices here, since\nyou set your own price per credit for your customers.","examples":[{"addOns":[{"creditsOnSuccess":0.5,"description":"Finds a professional email address for the contact. Charged once per lead, only on success.","parameter":"getEmails"}],"baseCredits":3,"unit":"per_lead_delivered"}]},{"type":"null"}],"description":"How this signal is billed — unit, base credits, and any paid add-on. Credits only; convert to your own currency at your own negotiated rate."},"relatedSignalTypes":{"anyOf":[{"items":{"properties":{"signalTypeId":{"type":"string","title":"Signaltypeid","description":"The other signal type's id."},"note":{"type":"string","title":"Note","description":"What distinguishes the two, so you pick the right one."}},"type":"object","required":["signalTypeId","note"],"title":"RelatedSignalType","description":"Another signal type easy to confuse with this one, and what tells them apart.","examples":[{"note":"Both deliver LinkedIn engagement leads, but on different inputs: this signal reads engagement on URLs you list; `dormant_linkedin_poster` finds people matching your persona/ICP filters who have stopped posting — no URL list, its own targeting.","signalTypeId":"dormant_linkedin_poster"}]},"type":"array"},{"type":"null"}],"title":"Relatedsignaltypes","description":"Other signal types this one is easy to confuse with — a narrower watchlist sibling, the umbrella `account_watchlist` it can also be watched through, or a differently-targeted signal that looks similar in a UI. Check this before building a picker that merges two signal types into one toggle."}},"type":"object","required":["signalTypeId","name","description","category","kind","creditsPerLead","createEndpoint"],"title":"PublicSignalType","description":"One signal type in the public catalog.","examples":[{"category":"competitive_intelligence","configParameters":{"companySizeFilters":{"description":"Only include leads from companies of these sizes","items":{"enum":["Self-employed","1-10","11-50","51-200","201-500","501-1000","1001-5000","5001-10000","10001+"]},"type":"array"},"getEmails":{"default":false,"description":"Enable email enrichment (0.5 credit/lead, charged only on success)","type":"boolean"},"linkedinCompanyUrls":{"description":"Competitor LinkedIn company page URLs to monitor for new connections","items":{"type":"string"},"type":"array"},"targetPersonas":{"description":"Persona names to keep (see GET /api/v1/personas)","items":{"type":"string"},"type":"array"}},"createEndpoint":"/api/v1/signals/competitor-connections","creditsPerLead":5,"deprecatedCreateEndpoints":["/api/v1/signals/competitor-relationships"],"description":"Get the new 1st-degree LinkedIn connections of your competitors' salespeople — typically their prospects and customers. Input competitor LinkedIn company URLs; each new connection matching your persona/ICP config is pushed to your webhook as an enriched lead.","kind":"signal","name":"Competitor Connections","outputFields":["signal.type","signal.tracked_company","contact.first_name","contact.last_name","contact.email","contact.title","contact.linkedin_profile_url","contact.matched_persona","company.name","company.website","company.linkedin_url"],"pricingModel":{"addOns":[{"creditsOnSuccess":0.5,"description":"Finds a professional email address for the contact. Charged once per lead, only on success.","parameter":"getEmails"}],"baseCredits":3,"unit":"per_lead_delivered"},"relatedSignalTypes":[{"note":"Can also be watched as part of `account_watchlist`, the umbrella that combines this with every other event on one company list, billed at one flat rate.","signalTypeId":"account_watchlist"}],"signalTypeId":"competitor_relationship_monitoring","unknownParameters":"Any key not listed here is silently accepted and ignored — ignoring it is NOT an error, but it also does nothing. A key you invent (e.g. a results-count limit) has no effect; only the keys listed in `configParameters` change behaviour."}]},"type":"array","title":"Signaltypes"}},"type":"object","required":["signalTypes"],"title":"PublicSignalTypesResponse","description":"The signal library — every signal type you can create via the API."}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/signals":{"get":{"tags":["Account Management"],"summary":"List signals","description":"View all your configured lead detection signals and their current status — see which ones are active, how many leads they detected today and in total, and review each signal's full configuration.\n\n**Input:** API authentication (via API key); optional query filters: `status` (`active` or `paused`), `signalTypeId` (filter by signal type, e.g., `competitor_relationship_monitoring`, `job_changes`), and `createdByThisKey` (`true` returns only the signals created with the API key making the call, instead of every signal on the account — use it to stop a staging integration from seeing production signals; signals created in the dashboard belong to no key and are never returned when it is `true`).\n\n**Output:** An array of signals, each with: id, name, status, signalTypeId, full config (the criteria you're monitoring: linkedinCompanyUrls, targetPersonas, locations, excludedTitles, etc.), webhookUrl, dailyLeadLimit, leadsToday, leadsTotal, duplicateHandling policy, and createdAt/updatedAt/lastLeadAt timestamps. Also returns a count of total signals.\n\n**Signals waiting on you:** `actionRequired=true` returns only the active signals that produce nothing until you act — a New Decision Maker or Account watchlist whose company matching waits for your confirmation (`MATCHING_CONFIRMATION_REQUIRED`), a Company Followers signal whose follower extraction waits for a quote (`QUOTE_REQUIRED`), or one whose extraction stopped because a LinkedIn company page it names does not exist (`COMPANY_PAGE_UNAVAILABLE`) — each with its `warnings`, which give the quote and the call that unblocks it. Poll it from a dashboard, or let us tell you: when a signal starts waiting on you, the account owners get an email and the signal's `webhookUrl` receives a `signal.action_required` event (see the Webhooks section), followed by `signal.action_resolved` once it no longer waits.","operationId":"list_signals_api_v1_signals_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status: active, paused","title":"Status"},"description":"Filter by status: active, paused"},{"name":"signalTypeId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by signal type","title":"Signaltypeid"},"description":"Filter by signal type"},{"name":"ids","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Fetch only these signals — a comma-separated list of ids (e.g. ?ids=id1,id2,id3). Up to 100 ids per request; for more, make multiple calls or page the full list with limit/offset.","title":"Ids"},"description":"Fetch only these signals — a comma-separated list of ids (e.g. ?ids=id1,id2,id3). Up to 100 ids per request; for more, make multiple calls or page the full list with limit/offset."},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":200,"minimum":1},{"type":"null"}],"description":"Max signals to return (pagination). Omit to return all.","title":"Limit"},"description":"Max signals to return (pagination). Omit to return all."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of signals to skip (pagination).","default":0,"title":"Offset"},"description":"Number of signals to skip (pagination)."},{"name":"actionRequired","in":"query","required":false,"schema":{"type":"boolean","description":"`true` returns only the active signals that produce nothing until you act — a watchlist whose company matching waits for your confirmation, a Company Followers signal whose extraction waits for a quote — each with its `warnings`, which say what to do and which call does it. Default `false`.","default":false,"title":"Actionrequired"},"description":"`true` returns only the active signals that produce nothing until you act — a watchlist whose company matching waits for your confirmation, a Company Followers signal whose extraction waits for a quote — each with its `warnings`, which say what to do and which call does it. Default `false`."},{"name":"createdByThisKey","in":"query","required":false,"schema":{"type":"boolean","description":"Return only the signals created with the API key making this call, instead of every signal on the account. Use it to keep a staging integration from seeing production signals. Signals created in the dashboard belong to no key and are never returned when this is true.","default":false,"title":"Createdbythiskey"},"description":"Return only the signals created with the API key making this call, instead of every signal on the account. Use it to keep a staging integration from seeing production signals. Signals created in the dashboard belong to no key and are never returned when this is true."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"signals":{"items":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"warnings":{"anyOf":[{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array"},{"type":"null"}],"title":"Warnings","description":"Present only with `actionRequired=true`: every warning of the signal, as GET /api/v1/signals/{signal_id} returns them, including the one that says what you need to do (`MATCHING_CONFIRMATION_REQUIRED`, `QUOTE_REQUIRED` or `COMPANY_PAGE_UNAVAILABLE`)."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalListItem","description":"A signal as listed by GET /api/v1/signals.","example":{"config":{"excludedCompanySizeFilters":[],"excludedCompanyUrls":[],"excludedIndustryFilters":[],"excludedLocations":["Paris"],"excludedTitles":[],"getEmails":true,"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist"],"locations":["France"],"targetPersonas":["Sales Director","CEO"]},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"Tech competitors in France","signalTypeId":"competitor_relationship_monitoring","status":"active","updatedAt":"2026-03-16T08:00:00Z","webhookUrl":"https://your-server.com/webhooks/rodz"}},"type":"array","title":"Signals"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["signals","total"],"title":"PublicSignalListResponse","description":"list of signals for public API.","examples":[{"signals":[{"config":{"targetPersonas":["Head of Sales"]},"createdAt":"2026-10-09T09:12:00+00:00","dailyLeadLimit":100,"duplicateHandling":"refuse","id":"d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f","leadsToday":0,"leadsTotal":0,"name":"Key accounts - new decision makers","signalTypeId":"new_decision_maker_watchlist","status":"active","updatedAt":"2026-10-09T09:15:00+00:00","warnings":[{"code":"MATCHING_CONFIRMATION_REQUIRED","field":"companies","message":"12,000 companies on this list must be matched to their LinkedIn company page before they can be watched, for at most 600.0 credits (0.05 per company; companies already matched are free). Nothing is matched or charged until you confirm with POST /api/v1/watchlists/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/companies/confirm-matching and {\"confirm\": true}.","severity":"warning","values":["600.0","12000"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}],"total":1}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"status","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/signals/{signal_id}":{"get":{"tags":["Account Management"],"summary":"Get signal","description":"Retrieve your signal's configuration and current performance metrics—check how many leads it generated today and lifetime, see when it last delivered leads, and verify your targets and delivery settings are correct.\n\n**Input:** the signal ID in the path.\n\n**Output:** your signal's metadata (`name`, `signalTypeId`, `status`, `createdAt`, `updatedAt`), configuration with targets and filters (`config`), delivery settings (`webhookUrl`, `dailyLeadLimit`, `duplicateHandling`), and current performance metrics (`leadsToday`, `leadsTotal`, `lastLeadAt`).\n\nThe response also carries two fields that make the configuration readable as it runs: `applied` (settings in force where they differ from `config` — a `maxJobAgeDays` below the minimum is shown at the minimum) and `warnings` (filter values that are probably not what you meant). Both are computed from the stored configuration, so a signal created before these fields existed reports them too.","operationId":"get_signal_api_v1_signals__signal_id__get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"PublicSignalResponse","description":"A single signal: create, GET /signals/{id} and PATCH.\n\nIt carries two fields the list does not. A customer reads their stored\n`config` back and assumes it is the one in force; on `job_changes` three\nfields were not (`maxJobAgeDays` 90 stored / 180 applied, `publishedDate`\nstored and never read, `allowUnknownCompanySize` true and applied false),\nwith nothing anywhere saying so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}},"patch":{"tags":["Account Management"],"summary":"Update signal","description":"Pause or resume a signal, change its filters, its webhook endpoint or its daily lead limit — without recreating it or losing its lead history.\n\n**Input:** `name` (new signal display name), `webhookUrl` (new endpoint URL where leads are delivered), `config`, `dailyLeadLimit` (max leads per day, 1–999,999), `duplicateHandling` (duplicate-lead policy: `refuse` = never re-accept a lead already delivered, `allow` = always accept, or `Xd` = accept again after X days, e.g. `7d`), `status` (active or paused).\n\n`config` **is merged into the stored configuration**: send only the fields you want to change, and every field you omit keeps its current value. To clear a list, send it empty (for example `targetPersonas: []`). A complete object still overwrites every field it carries.\n\n**Watched lists:** on a watchlist, `companies` (or `profiles` on a job-change watchlist) sent in `config` are **added** to the watched list, exactly as `POST /api/v1/watchlists/{signalId}/companies` (or `/profiles`) does in its default `append` mode — nothing is removed, and the list is not echoed back in `config`. To replace the whole list use that endpoint with `mode: replace`; to remove one entry, `DELETE` it. A LinkedIn link in a company list that names no company (a person's profile, a post) is refused with 422 `INVALID_COMPANY_ENTRY`; a Sales Navigator company link is read as the company's LinkedIn id.\n\n**Connection signals:** people added to `linkedinProfileUrls` start being watched, and people removed stop being watched, as on activation.\n\n**Output:** the updated signal with its stored `config`, `applied` and `warnings` (see GET), status, real-time lead metrics (leads today + cumulative total since creation), and timestamps (created, updated, last lead received). When the PATCH carried a watched list, `watchlist` reports how many entries are now watched, were already watched, or were rejected.","operationId":"update_signal_api_v1_signals__signal_id__patch","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"destinations":{"anyOf":[{"$ref":"#/components/schemas/SignalDestinations"},{"type":"null"}],"description":"Route this signal's qualified leads to connected integrations (in addition to webhookUrl). Each named provider must already be connected on your account, or the call returns 409 INTEGRATION_NOT_CONNECTED."},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"MERGED into the stored configuration: send only the fields you want to change, every field you leave out keeps its current value. To clear a list, send it empty (e.g. `\"targetPersonas\": []`). A complete object still overwrites every field it carries. On a watchlist, `companies` (or `profiles` on a job-change watchlist) sent here are ADDED to the watched list, exactly as `POST /api/v1/watchlists/{signalId}/companies` in its default `append` mode: nothing is removed, and `watchlist` in the response reports what was taken in. To replace the list or remove an entry, use that endpoint with `mode: replace`, or `DELETE` on the entry.","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"anyOf":[{"type":"integer","maximum":999999.0,"minimum":1.0},{"type":"null"}],"title":"Dailyleadlimit"},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Signal status: active, paused"}},"type":"object","title":"PublicSignalUpdate","description":"Update a signal via the public API."}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"status":{"type":"string","title":"Status"},"signalTypeId":{"type":"string","title":"Signaltypeid"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Signal-specific configuration","examples":[{"linkedinCompanyUrls":["https://linkedin.com/company/acme"]}]},"dailyLeadLimit":{"type":"integer","title":"Dailyleadlimit"},"leadsToday":{"type":"integer","title":"Leadstoday"},"leadsTotal":{"type":"integer","title":"Leadstotal"},"duplicateHandling":{"type":"string","title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)"},"createdAt":{"type":"string","title":"Createdat"},"updatedAt":{"type":"string","title":"Updatedat"},"lastLeadAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastleadat"},"applied":{"additionalProperties":true,"type":"object","title":"Applied","description":"Settings this signal runs with where they differ from `config`, keyed like `config`. `{}` when every stored setting is applied as stored. A `null` value means the stored field is not used by this signal. Every entry is explained by a warning naming the same field."},"warnings":{"items":{"$ref":"#/components/schemas/SignalConfigWarning"},"type":"array","title":"Warnings","description":"What you should know about this configuration: values applied differently from what is stored, and filter values that are probably not what you meant. Computed from the stored configuration, so they appear on GET as well as on create and update - a signal created before these fields existed reports them too. Never an error: the signal is created or updated regardless."},"watchlist":{"anyOf":[{"properties":{"watched":{"type":"integer","title":"Watched","description":"Entries now being watched by this signal (people, or companies)."},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — a LinkedIn URL that is not a personal profile, or a company row with neither a name nor a domain.","default":0},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on this signal's list, left unchanged.","default":0}},"type":"object","required":["watched"],"title":"WatchlistImportResult","description":"What the watchlist create actually took in.\n\nReturned only for watchlist signals. The rejected/unresolved counts are\nsurfaced rather than swallowed: a watchlist that quietly dropped half its\nlist looks identical to a healthy one until the leads never arrive.","examples":[{"alreadyWatched":0,"rejected":1,"watched":2}]},{"type":"null"}],"description":"How much of the list you sent is actually being watched. Check `rejected` against what you submitted before assuming the signal is covering your whole list."}},"type":"object","required":["id","name","status","signalTypeId","dailyLeadLimit","leadsToday","leadsTotal","duplicateHandling","createdAt","updatedAt"],"title":"WatchlistSignalResponse","description":"Create response for the two watchlist signals.\n\nA separate model rather than an optional field on ``PublicSignalResponse``:\nthis spec inlines the response schema at every signal endpoint (36 of them),\nso carrying the extra object on the shared model documented a phantom\n``watchlist`` field on 34 endpoints that never return one — and doubled the\nsize of the published spec to say so.","example":{"applied":{"allowUnknownCompanySize":false,"maxJobAgeDays":180},"config":{"companySizeFilters":["201-500","501-1000"],"getEmails":true,"jobTitles":["CTO"],"locations":["France"],"maxJobAgeDays":90},"createdAt":"2026-01-15T10:30:00Z","dailyLeadLimit":50,"duplicateHandling":"refuse","id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","lastLeadAt":"2026-03-15T14:22:00Z","leadsToday":3,"leadsTotal":127,"name":"CTOs changing jobs in France","signalTypeId":"job_changes","status":"active","updatedAt":"2026-03-16T08:00:00Z","warnings":[{"code":"VALUE_BELOW_MINIMUM","field":"maxJobAgeDays","message":"`maxJobAgeDays` is 90; this signal applies 180. Job changes are delivered up to 180 days after the start date, and a shorter window is raised to that minimum.","severity":"info","values":["90"]}],"webhookUrl":"https://your-server.com/webhooks/rodz"}}}}},"400":{"description":"Invalid update: bad status value, or an unrecognized location filter","content":{"application/json":{"examples":{"invalid_status":{"summary":"Unsupported status value","value":{"error":{"code":"INVALID_STATUS","message":"Status must be 'active' or 'paused'"}}},"invalid_location":{"summary":"Unrecognized location in the location filter","value":{"error":{"code":"INVALID_LOCATION","message":"Unrecognized location(s): Frannce. Use a country, region, or city name (e.g. 'France', 'Paris'). Validate names first with GET /api/v1/enrichment/validate-location.","invalid_locations":["Frannce"]}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}},"delete":{"tags":["Account Management"],"summary":"Delete signal","description":"Stop monitoring and receiving new leads from a signal configuration—all historical leads are retained in your account, webhooks, and CRM/outreach integrations (HubSpot, Google Sheets, etc.).\n\n**Input:** `signal_id` (path parameter; no request body)\n\n**Output:** HTTP 204 No Content. The signal immediately stops generating new leads. All previously detected leads remain in your systems with their enrichment data intact; only the ongoing monitoring is halted.","operationId":"delete_signal_api_v1_signals__signal_id__delete","security":[{"BearerAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","title":"Signal Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signal_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/company-posts":{"get":{"tags":["Enrichment"],"summary":"Get company posts","description":"Monitor a company's public LinkedIn posts — their content strategy, product announcements, and hiring signals, plus audience engagement (reactions, comments, shares, reaction types).\n\n**Input:** the company's LinkedIn page URL (`company`), or its LinkedIn company ID (`companyId`), or company universal name / handle (`companyUniversalName` — the last segment of the company URL, fastest). Filter posts to a time window with `scrapePostedLimit` (`1h`, `24h`, `week`, `month`, `3months`, `6months`, or `year`). Paginate with `paginationToken` (or `page` for numeric pagination).\n\n**Output:** each page returns an array of posts from the company's feed, newest first, with full content, media (images, links, articles), author metadata (company name, logo, website), and engagement stats (reaction counts by type, comment count, share count). Pagination metadata (token, page size, and totals when available) lets you fetch all posts. 0.5 credits per page; pages are returned even if empty (and not billed).","operationId":"enrichment_company_posts_api_v1_enrichment_company_posts_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"company","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"LinkedIn company URL","title":"Company"},"description":"LinkedIn company URL"},{"name":"companyId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"LinkedIn company ID (faster)","title":"Companyid"},"description":"LinkedIn company ID (faster)"},{"name":"companyUniversalName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company universal name (last part of URL)","title":"Companyuniversalname"},"description":"Company universal name (last part of URL)"},{"name":"scrapePostedLimit","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Time filter: 1h, 24h, week, month, 3months, 6months, year","title":"Scrapepostedlimit"},"description":"Time filter: 1h, 24h, week, month, 3months, 6months, year"},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Page number","title":"Page"},"description":"Page number"},{"name":"paginationToken","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pagination token from previous page","title":"Paginationtoken"},"description":"Pagination token from previous page"}],"responses":{"200":{"description":"Recent posts for the company page.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"elements":{"anyOf":[{"items":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"author":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"universalName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universalname"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"\"profile\" or \"company\""},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"info":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Info"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"websiteLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Websitelabel"},"avatar":{"anyOf":[{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_PostImage"},{"type":"null"}]},"urn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Urn"}},"additionalProperties":true,"type":"object","title":"_PostAuthor"},{"type":"null"}]},"postedAt":{"anyOf":[{"properties":{"timestamp":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timestamp"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"postedAgoShort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagoshort"},"postedAgoText":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagotext"}},"additionalProperties":true,"type":"object","title":"_PostedAt"},{"type":"null"}]},"postImages":{"anyOf":[{"items":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_PostImage"},"type":"array"},{"type":"null"}],"title":"Postimages"},"shareUrn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shareurn"},"shareLinkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sharelinkedinurl"},"entityId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entityid"},"engagement":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"likes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Likes"},"comments":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Comments"},"shares":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Shares"},"reactions":{"anyOf":[{"items":{"properties":{"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count"}},"additionalProperties":true,"type":"object","title":"_PostReactionCount"},"type":"array"},{"type":"null"}],"title":"Reactions"}},"additionalProperties":true,"type":"object","title":"_PostEngagement"},{"type":"null"}]},"contentAttributes":{"anyOf":[{"items":{"properties":{"start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start"},"length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Length"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"Entity kind, e.g. \"COMPANY_NAME\" or \"PROFILE_MENTION\""},"hyperlink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hyperlink"},"textLink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Textlink"},"company":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"},"universalName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universalname"}},"additionalProperties":true,"type":"object","title":"_PostContentEntityCompany","description":"Company referenced by a COMPANY_NAME entity in ``contentAttributes``."},{"type":"null"}]},"profile":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"}},"additionalProperties":true,"type":"object","title":"_PostContentEntityProfile","description":"Person referenced by a PROFILE_MENTION entity in ``contentAttributes``."},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_PostContentAttribute","description":"One span of rich text inside ``content``.\n\n``start``/``length`` index into ``content``. Which nested object is present\nfollows ``type``: ``COMPANY_NAME`` carries ``company``, ``PROFILE_MENTION``\ncarries ``profile``. Both are optional because a hyperlink entity carries\nneither."},"type":"array"},{"type":"null"}],"title":"Contentattributes","description":"Rich-text spans inside `content` (mentions, links)"},"article":{"anyOf":[{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link"},"linkLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linklabel"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"image":{"anyOf":[{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_PostArticleImage"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_PostArticle","description":"Link preview when the post shares an external article."},{"type":"null"}],"description":"Link preview, when the post shares one"},"socialContent":{"anyOf":[{"properties":{"hideCommentsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidecommentscount"},"hideReactionsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidereactionscount"},"hideSocialActivityCounts":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidesocialactivitycounts"},"hideShareAction":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hideshareaction"},"hideSendAction":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidesendaction"},"hideRepostsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hiderepostscount"},"hideViewsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hideviewscount"},"showContributionExperience":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Showcontributionexperience"},"showSocialDetail":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Showsocialdetail"},"shareUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shareurl"},"trustInterventionBanner":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trustinterventionbanner"}},"additionalProperties":true,"type":"object","title":"_PostSocialContent","description":"Display flags LinkedIn attaches to the post."},{"type":"null"}]},"header":{"anyOf":[{"properties":{"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"}},"additionalProperties":true,"type":"object","title":"_PostHeader"},{"type":"null"}]},"postVideo":{"anyOf":[{"properties":{"thumbnailUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnailurl"},"videoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Videourl"}},"additionalProperties":true,"type":"object","title":"_PostVideo","description":"Present when the post carries a native video."},{"type":"null"}],"description":"Native video attached to the post"},"document":{"anyOf":[{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"transcribedDocumentUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcribeddocumenturl"},"coverPages":{"anyOf":[{"items":{"properties":{"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"imageUrls":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Imageurls"}},"additionalProperties":true,"type":"object","title":"_PostDocumentCoverPage"},"type":"array"},{"type":"null"}],"title":"Coverpages"}},"additionalProperties":true,"type":"object","title":"_PostDocument","description":"Present when the post carries a document/carousel. Profile posts only."},{"type":"null"}],"description":"Attached document/carousel. Profile posts only."},"repostedBy":{"anyOf":[{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"},"universalName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universalname"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"}},"additionalProperties":true,"type":"object","title":"_PostRepostedBy","description":"Original author when this element is a repost. Profile posts only."},{"type":"null"}],"description":"Original author when this element is a repost. Profile posts only."},"repostedAt":{"anyOf":[{"properties":{"timestamp":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timestamp"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"postedAgoShort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagoshort"},"postedAgoText":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagotext"}},"additionalProperties":true,"type":"object","title":"_PostedAt"},{"type":"null"}],"description":"When the repost happened. Profile posts only."},"comments":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Comments","description":"Always an empty array on the post-list endpoints — a post list does not expand comments, regardless of `engagement.comments`. Use GET /enrichment/post-comments to fetch them."}},"additionalProperties":true,"type":"object","title":"_PostElement"},"type":"array"},{"type":"null"}],"title":"Elements"},"pagination":{"anyOf":[{"properties":{"totalElements":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalelements"},"totalPages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalpages"},"pageNumber":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pagenumber"},"previousElements":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Previouselements"},"pageSize":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pagesize"},"paginationToken":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paginationtoken"}},"additionalProperties":true,"type":"object","title":"_PostsPagination"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_PostsData"},{"type":"null"}],"description":"Posts payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Why no posts were returned, when `data` is null. Otherwise null."}},"additionalProperties":true,"type":"object","title":"PostsResponse","description":"Typed response for the posts endpoints (profile & company)."},"example":{"data":{"elements":[{"id":"7469496437156925441","linkedinUrl":"https://www.linkedin.com/posts/marie-dupont_hiring-activity-7469496437156925441-88oN","content":"We just shipped our new analytics dashboard 🎉 — and we're hiring two senior engineers to take it further. DM me if you're interested.","contentAttributes":[{"start":0,"length":7,"type":"COMPANY_NAME","company":{"id":"5366","name":"Lemlist","linkedinUrl":"https://www.linkedin.com/company/lemlist/"}}],"author":{"id":"ACoAAB1exampleProfileUrnZ","type":"company","name":"Lemlist","linkedinUrl":"https://www.linkedin.com/company/lemlist/","info":"Sales engagement platform","website":"https://lemlist.com","websiteLabel":"Visit our site","avatar":{"url":"https://media.licdn.com/dms/image/v2/example/profile-displayphoto-shrink_800_800/0/1736826818808","width":800,"height":800},"urn":"251749025"},"postedAt":{"timestamp":1780866727151,"date":"2026-05-31T14:30:00.000Z","postedAgoShort":"1d","postedAgoText":"1 day ago • Visible to anyone on or off LinkedIn"},"postImages":[{"url":"https://media.licdn.com/dms/image/v2/example/feedshare-image-high-res/0/1780420456539","width":557,"height":896}],"article":{},"socialContent":{"hideCommentsCount":false,"hideReactionsCount":false,"hideSocialActivityCounts":false,"hideShareAction":false,"hideSendAction":false,"hideRepostsCount":false,"hideViewsCount":false,"hideReactAction":false,"hideCommentAction":false,"shareUrl":"https://www.linkedin.com/posts/marie-dupont_hiring-activity-7469496437156925441-88oN","showContributionExperience":false,"showSocialDetail":true},"comments":[],"header":{},"entityId":"7469496437156925441","shareUrn":"urn:li:ugcPost:7469496436737495040","shareLinkedinUrl":"https://www.linkedin.com/feed/update/urn:li:ugcPost:7469496436737495040","engagement":{"id":"7469496436737495042","likes":312,"comments":21,"shares":8,"reactions":[{"type":"LIKE","count":250},{"type":"PRAISE","count":40},{"type":"EMPATHY","count":22}]}}],"pagination":{"totalElements":0,"totalPages":0,"pageNumber":1,"previousElements":0,"pageSize":50,"paginationToken":"dXJuOmxpOmFjdGl2aXR5Ojc0NDU5Mzc2MjI3MTMyMjExMjA="}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Input should be a valid integer, unable to parse string as an integer","details":{"field":"page","message":"Input should be a valid integer, unable to parse string as an integer"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/company-search":{"get":{"tags":["Enrichment"],"summary":"Search for companies","description":"Find companies by what they are called, by what they *do*, or purely by their\nfirmographics - and get back the canonical company each time: its LinkedIn company page URL plus key\ndetails. Pass a name to resolve messy user input, pass a phrase like `\"sales engagement platform\"` to\nfind companies describing themselves that way, or pass no keywords at all and build a target list from\nfilters alone (e.g. every software company in France with 51-200 employees).\n\n**Cost:** 0.5 credits per call (billed only when at least one company is returned; empty results are free).\n\n**Input:** at least one of `keywords`, `location`, `geoId`, `companySize` or `industryId` is required\n(`page` alone is not enough).\n- `keywords` - matched against the company page: its name, tagline **and** description. So\n  `\"precision outbound\"` returns companies whose about-text says it, not just ones with it in their\n  name. Optional when you filter by firmographics instead.\n- `location` - filter matches by location text (e.g. `\"France\"`). Optional.\n- `geoId` - filter by LinkedIn geo ID (resolve one with `/enrichment/linkedin-geo-id`); overrides `location`. Optional.\n- `companySize` - comma-separated size bands to filter by: `1-10`, `11-50`, `51-200`, `201-500`, `501-1000`, `1001-5000`, `5001-10000`, `10001+`. Optional.\n- `industryId` - one or more comma-separated LinkedIn industry IDs. Optional.\n- `page` - 1-based page number. Optional.\n\n**Output** - `data` contains:\n- `elements` - array of matching companies, each: `name`, `linkedinUrl`, `universalName` (the `/company/<slug>` handle), `industry`, `location`, `followers`, `logoUrl` (any field may be null).\n- `pagination` - `totalPages`, `totalElements`, `pageNumber`, `pageSize`. Page through results by incrementing the `page` parameter up to `totalPages`.\n\n**Use cases:**\n- **Resolve name to LinkedIn URL** - feed the URL into `/enrichment/firmographic`, `/enrichment/people-search`, or a signal to enrich or monitor the company.\n- **Find companies by what they do** - search the phrase your market uses (`\"sales engagement platform\"`, `\"fractional CFO\"`) to surface competitors, partners or acquisition targets that never mention it in their name.\n- **Build a target account list** - skip `keywords` and filter on `companySize` + `industryId` + `geoId` to page through every company matching your ICP, then feed them into signals or enrichment.\n- **Company picker / autocomplete** - power a type-ahead in your own app so users pick a company instead of pasting a URL.\n- **Canonicalize & de-duplicate** - match your own company records against their authoritative LinkedIn page.","operationId":"enrichment_company_search_api_v1_enrichment_company_search_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"keywords","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Keywords matched against the company page — name, tagline and description — so a phrase like 'sales engagement platform' finds companies describing themselves that way, not just ones with it in their name. Optional: omit it to discover companies by firmographics instead (at least one filter required).","title":"Keywords"},"description":"Keywords matched against the company page — name, tagline and description — so a phrase like 'sales engagement platform' finds companies describing themselves that way, not just ones with it in their name. Optional: omit it to discover companies by firmographics instead (at least one filter required)."},{"name":"location","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by location text (e.g. 'France')","title":"Location"},"description":"Filter by location text (e.g. 'France')"},{"name":"geoId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by LinkedIn geo ID (overrides location)","title":"Geoid"},"description":"Filter by LinkedIn geo ID (overrides location)"},{"name":"companySize","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated size bands: 1-10,11-50,51-200,201-500,501-1000,1001-5000,5001-10000,10001+","title":"Companysize"},"description":"Comma-separated size bands: 1-10,11-50,51-200,201-500,501-1000,1001-5000,5001-10000,10001+"},{"name":"industryId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"One or more comma-separated LinkedIn industry IDs, e.g. `4` (Software Development) or `4,96`. Look IDs up by name with `GET /api/v1/enrichment/linkedin-industries?search=software` — they are not guessable and do not appear in company payloads.","title":"Industryid"},"description":"One or more comma-separated LinkedIn industry IDs, e.g. `4` (Software Development) or `4,96`. Look IDs up by name with `GET /api/v1/enrichment/linkedin-industries?search=software` — they are not guessable and do not appear in company payloads."},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Page number (1-based)","title":"Page"},"description":"Page number (1-based)"}],"responses":{"200":{"description":"One page of companies matching the name, each with its LinkedIn URL.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"elements":{"anyOf":[{"items":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Company name"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl","description":"Company LinkedIn page URL"},"universalName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universalname","description":"LinkedIn vanity name / slug (the '/company/<slug>' segment)"},"industry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Industry","description":"Industry classification (may be null)"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Headquarters location text, e.g. 'Paris, France' (may be null)"},"followers":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Followers","description":"Follower count label, e.g. '12K followers' (may be null)"},"logoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logourl","description":"Company logo image URL (may be null)"}},"additionalProperties":true,"type":"object","title":"_CompanySearchElement"},"type":"array"},{"type":"null"}],"title":"Elements","description":"Matching companies"},"pagination":{"anyOf":[{"properties":{"totalPages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalpages","description":"Total number of result pages"},"totalElements":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalelements","description":"Total number of matches"},"pageNumber":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pagenumber","description":"Current page (1-based)"},"pageSize":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pagesize","description":"Matches per page"}},"additionalProperties":true,"type":"object","title":"_CompanySearchPagination"},{"type":"null"}],"description":"Pagination metadata"}},"additionalProperties":true,"type":"object","title":"_CompanySearchData"},{"type":"null"}],"description":"One page of matching companies, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"CompanySearchResponse","description":"Typed response for /enrichment/company-search."},"example":{"data":{"elements":[{"name":"lemlist","linkedinUrl":"https://www.linkedin.com/company/lemlist/","universalName":"lemlist","industry":"Software Development","location":"New York, NY","followers":"54K followers","logoUrl":"https://media.licdn.com/dms/image/v2/C4E0BAQFBm8WYaagqQA/company-logo_100_100/company-logo_100_100/0/1677597233017/lemlist_logo"}],"pagination":{"totalPages":1,"totalElements":2,"pageNumber":1,"pageSize":50}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Input should be a valid integer, unable to parse string as an integer","details":{"field":"page","message":"Input should be a valid integer, unable to parse string as an integer"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/contact":{"get":{"tags":["Enrichment"],"summary":"Enrich a contact","description":"Find comprehensive professional profiles for any person — current company, work history, education, skills, and LinkedIn engagement — using a LinkedIn URL, email, or name+company combination.\n\n**Input:** at least one of: LinkedIn profile URL (`url`), email address (`email`), first/last name (`firstName`, `lastName`) or full name (`fullName`), or company identifiers (`companyName`, `domain`, `companyLinkedinUrl`). LinkedIn URL lookups return the richest data; email or name-based lookups may return fewer fields.\n\n**Data freshness:** `freshness=live` (default) fetches the profile at request time — the profile as it stands the moment you ask, 0.5 credits, typically 3-4 s. `freshness=cached` answers from a stored profile that is **never more than 8 days old**, at 0.25 credits (half price) and typically **under a second** (measured: ~0.8 s median against ~4 s for `live`). **If latency matters, integrate against `cached`** — in the normal case it returns exactly the same fields as `live`: same positions, same education entries, same company and school logos. A minority of cached answers are rebuilt from our own stored columns and omit `country`/`region`/`county`/`city`, `educationDetails` beyond `universitiesNamesList`, language proficiency, `certificationsList`, `isVerified`, `isCreator`, `isOpenLink`, `extractedGender`, `companyWebsite` and per-position `jobDescription`/`yearsInRole`; ask for `live` when you need a profile refreshed in the last minutes or must have every one of those on every call. Both rates are set against your monthly volume.\n\n**Output:** enriched contact record (`data.person`) with professional headline, current and past positions (with employment dates), education details, skills, languages, location, profile photo, follower/connection counts, and hiring status.","operationId":"enrichment_contact_api_v1_enrichment_contact_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"url","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"LinkedIn profile URL (e.g. https://www.linkedin.com/in/johndoe)","title":"Url"},"description":"LinkedIn profile URL (e.g. https://www.linkedin.com/in/johndoe)"},{"name":"email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Contact email address","title":"Email"},"description":"Contact email address"},{"name":"firstName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"First name (requires lastName)","title":"Firstname"},"description":"First name (requires lastName)"},{"name":"lastName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Last name (requires firstName)","title":"Lastname"},"description":"Last name (requires firstName)"},{"name":"fullName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full name (alternative to firstName + lastName)","title":"Fullname"},"description":"Full name (alternative to firstName + lastName)"},{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company domain (e.g. google.com)","title":"Domain"},"description":"Company domain (e.g. google.com)"},{"name":"companyName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company name","title":"Companyname"},"description":"Company name"},{"name":"companyLinkedinUrl","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company LinkedIn URL","title":"Companylinkedinurl"},"description":"Company LinkedIn URL"},{"name":"freshness","in":"query","required":false,"schema":{"enum":["live","cached"],"type":"string","description":"Data freshness. `live` (default): a fresh lookup, most current data — **0.5 credits**. `cached`: answered from a profile we already hold when we have a recent one — **0.25 credits** and near-instant instead of ~3s, at the cost of data that may be slightly less recent and a reduced field set. Same values and pricing as the bulk endpoint.","default":"live","title":"Freshness"},"description":"Data freshness. `live` (default): a fresh lookup, most current data — **0.5 credits**. `cached`: answered from a profile we already hold when we have a recent one — **0.25 credits** and near-instant instead of ~3s, at the cost of data that may be slightly less recent and a reduced field set. Same values and pricing as the bulk endpoint."}],"responses":{"200":{"description":"Enriched contact (`data.person`).","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"person":{"anyOf":[{"properties":{"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"middleName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Middlename"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"linkedInUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"linkedInId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinid"},"linkedinSalesLink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinsaleslink","description":"Sales Navigator profile URN token (e.g. ACoAAB...)"},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline"},"activeCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Activecompany"},"numberOfCurrentCompanies":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Numberofcurrentcompanies"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region"},"county":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"County"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"followers":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Followers","description":"Follower count as a string"},"followerCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Followercount"},"connectionsCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Connectionscount"},"isCreator":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Iscreator"},"isJobSeeker":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isjobseeker"},"isOpenLink":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isopenlink"},"isPremium":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ispremium"},"isVerified":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isverified"},"openProfileMessages":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Openprofilemessages"},"languages":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Languages","description":"Comma-separated language list"},"skillsList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skillslist","description":"Comma-separated skills"},"linkedinSummary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinsummary"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"extractedGender":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extractedgender","description":"Inferred gender when available: one of \"male\", \"female\", or \"\" (unknown)"},"formerCompaniesList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Formercompanieslist","description":"Comma-separated former company names"},"education":{"anyOf":[{"properties":{"universitiesNamesList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universitiesnameslist"},"educationDetails":{"anyOf":[{"items":{"properties":{"startedOn":{"anyOf":[{"properties":{"year":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Year"}},"additionalProperties":true,"type":"object","title":"_PersonEducationYear"},{"type":"null"}],"description":"Start year. Education dates are year-granular; no month is available."},"endedOn":{"anyOf":[{"properties":{"year":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Year"}},"additionalProperties":true,"type":"object","title":"_PersonEducationYear"},{"type":"null"}],"description":"End year. Year-granular, like startedOn."},"universityName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universityname"},"fieldsOfStudy":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Fieldsofstudy"},"socialUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Socialurl","description":"School LinkedIn URL, e.g. https://www.linkedin.com/company/15142508/"},"schoolId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schoolid","description":"LinkedIn school ID as a string, e.g. \"15142508\""},"schoolLogo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schoollogo","description":"School logo image URL (empty when the school has none)"}},"additionalProperties":true,"type":"object","title":"_PersonEducationDetail"},"type":"array"},{"type":"null"}],"title":"Educationdetails"}},"additionalProperties":true,"type":"object","title":"_PersonEducation"},{"type":"null"}]},"certificationsList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Certificationslist"},"certification":{"anyOf":[{"items":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Certification name, e.g. \"Machine Learning\""},"issuedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuedat","description":"Free text as displayed, e.g. \"Issued Jan 2017\" — not a date"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link","description":"URL of the certification itself"},"issuedBy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuedby","description":"Issuing organisation name"},"issuedByLink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuedbylink","description":"LinkedIn URL of the issuing organisation"},"issuedByLogo":{"anyOf":[{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"sizes":{"anyOf":[{"items":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_ContactCertificationLogoSize"},"type":"array"},{"type":"null"}],"title":"Sizes"}},"additionalProperties":true,"type":"object","title":"_ContactCertificationLogo"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_ContactCertification","description":"One certification on a person's profile.\n\nPreviously declared as a bare list (``items: {}``), so generated clients had\nto guess the field names — a customer reported silently producing all-null\nobjects for every certification (2026-08-05). Note ``issuedAt`` is free text\nas LinkedIn renders it (e.g. \"Issued Jan 2017\"), NOT a parseable date."},"type":"array"},{"type":"null"}],"title":"Certification","description":"Certification entries (empty when none)"},"currentCompanyDetail":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"jobTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitle"},"startTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"},"endTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime","description":"End date, or \"Present\" for current roles"},"yearsInCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsincompany"},"yearsInRole":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsinrole"},"jobDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescription"},"companyUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyurl","description":"Company LinkedIn URL for this position"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"companyId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyid","description":"LinkedIn company ID as a string, e.g. \"101088054\""},"companyLogo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylogo","description":"Company logo image URL (empty when unavailable)"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Where this role is based, e.g. \"Bordeaux, Nouvelle-Aquitaine, France\""},"employmentType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employmenttype","description":"Contract type as shown on the profile, e.g. \"Permanent\", \"Internship\""},"workplaceType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workplacetype","description":"Work arrangement, e.g. \"Hybrid\", \"Remote\", \"On-site\""}},"additionalProperties":true,"type":"object","title":"_PersonCompanyDetail","description":"One entry of currentCompanyDetail / pastCompaniesDetails (same shape)."},"type":"array"},{"type":"null"}],"title":"Currentcompanydetail"},"pastCompaniesDetails":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"jobTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitle"},"startTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"},"endTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime","description":"End date, or \"Present\" for current roles"},"yearsInCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsincompany"},"yearsInRole":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsinrole"},"jobDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescription"},"companyUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyurl","description":"Company LinkedIn URL for this position"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"companyId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyid","description":"LinkedIn company ID as a string, e.g. \"101088054\""},"companyLogo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylogo","description":"Company logo image URL (empty when unavailable)"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Where this role is based, e.g. \"Bordeaux, Nouvelle-Aquitaine, France\""},"employmentType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employmenttype","description":"Contract type as shown on the profile, e.g. \"Permanent\", \"Internship\""},"workplaceType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workplacetype","description":"Work arrangement, e.g. \"Hybrid\", \"Remote\", \"On-site\""}},"additionalProperties":true,"type":"object","title":"_PersonCompanyDetail","description":"One entry of currentCompanyDetail / pastCompaniesDetails (same shape)."},"type":"array"},{"type":"null"}],"title":"Pastcompaniesdetails"},"photoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photourl"},"websites":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Websites","description":"Comma-separated personal website URLs"},"hiring":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hiring"},"registeredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Registeredat","description":"LinkedIn registration date (YYYY-MM-DD)"},"locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locale","description":"Profile locale, e.g. \"en\", \"fr\""}},"additionalProperties":true,"type":"object","title":"_PersonPerson","description":"The enriched LinkedIn person object (``data.person``)."},{"type":"null"}],"description":"The enriched person, or null if no match"}},"additionalProperties":true,"type":"object","title":"_PersonData","description":"``data`` wrapper for the person endpoints — holds a single ``person``."},{"type":"null"}],"description":"Enriched contact payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"ContactResponse","description":"Typed response for ``GET /enrichment/contact``."},"example":{"data":{"person":{"firstName":"Marie","middleName":"","lastName":"Dupont","name":"Marie Dupont","linkedInUrl":"https://www.linkedin.com/in/marie-dupont","linkedInId":"251749025","linkedinSalesLink":"ACoAAB1exampleProfileUrnZ","headline":"VP Engineering at Lemlist","activeCompany":"Lemlist","numberOfCurrentCompanies":"1","location":"Paris, Île-de-France, France","country":"France","region":"Île-de-France","county":"Paris","city":"Paris","followers":"4821","followerCount":4821,"connectionsCount":500,"isCreator":false,"isJobSeeker":false,"isOpenLink":false,"isPremium":true,"isVerified":false,"openProfileMessages":true,"languages":"French, English","skillsList":"Python, Distributed Systems, Team Leadership","linkedinSummary":"Engineering leader focused on developer tooling and reliability.","companyWebsite":"https://lemlist.com","extractedGender":"","formerCompaniesList":"Datadog, Algolia","education":{"universitiesNamesList":"INSA Lyon","educationDetails":[{"startedOn":{"year":"2008"},"endedOn":{"year":"2013"},"universityName":"INSA Lyon","fieldsOfStudy":["Computer Science"],"socialUrl":"https://www.linkedin.com/company/15093/","schoolId":"15093","schoolLogo":"https://media.licdn.com/dms/image/v2/example/company-logo_400_400/0/1725378371996"}]},"certificationsList":"","certification":[],"currentCompanyDetail":[{"companyName":"Lemlist","jobTitle":"VP Engineering","startTime":"Mar-2021","endTime":"Present","yearsInCompany":"5 yrs","yearsInRole":"5 yrs","jobDescription":"","companyUrl":"https://www.linkedin.com/company/18394190/","companyWebsite":"https://lemlist.com","companyId":"18394190","companyLogo":"https://media.licdn.com/dms/image/v2/example/company-logo_400_400/0/1736784969376","location":"Paris, Ile-de-France, France","employmentType":"Permanent","workplaceType":"Hybrid"}],"pastCompaniesDetails":[{"companyName":"Datadog","jobTitle":"Staff Engineer","startTime":"2017","endTime":"Feb-2021","yearsInCompany":"4 yrs","yearsInRole":"4 yrs","companyUrl":"https://www.linkedin.com/company/1157/","companyWebsite":"https://datadoghq.com","companyId":"1157","companyLogo":"","location":"Paris, Ile-de-France, France","employmentType":"Permanent","workplaceType":"On-site"}],"photoUrl":"https://media.licdn.com/dms/image/v2/example/profile-displayphoto-shrink_800_800/0/1736826818808","websites":"https://mariedupont.dev","hiring":true,"registeredAt":"2009-04-12","locale":"en"}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Input should be one of the permitted values","details":{"field":"freshness","message":"Input should be one of the permitted values"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/contacts/bulk":{"post":{"tags":["Enrichment"],"summary":"Bulk-enrich contacts (webhook delivery)","description":"Enrich up to **50,000** LinkedIn profiles in a single call.\n\nBulk enrichment runs **asynchronously**: this call returns immediately with a `batchId`, and the results arrive when the batch completes.\n\n**Data freshness — you choose with `freshness`:**\n- `live` (default): a fresh scrape of every profile — most current data, **0.5 credits per match**. Slower; very large batches can take a while.\n- `cached`: served from our directory cache — **0.25 credits per match (half price)** and much faster (typically ~1 min). Cached profiles are **never more than 8 days old**.\n\n**Delivery — you choose with `deliveryMode`:**\n- `webhook` (default): the **full enriched batch** is POSTed to your `webhookUrl` when it finishes. Simplest for small/medium batches.\n- `poll`: results are **held for you to fetch** at `GET /api/v1/enrichment/contacts/bulk/{batchId}` (paginated). Nothing large is pushed; if you also pass a `webhookUrl`, you receive a small **ready-notification** (not the full payload) when the batch is done.\n\n> **Recommended: use `deliveryMode: poll` for any request over 5,000 profiles.** A completed 50,000-profile batch is a 50–150 MB payload; polling lets you pull it in pages instead of receiving one very large POST (which many servers reject or time out on).\n\n**Cost:** per successfully enriched profile — **0.5 credits** (`freshness: live`) or **0.25 credits** (`freshness: cached`). No charge for profiles that can't be matched, and the same whether you poll or use a webhook.\n\n**Request:** `profiles` (each a LinkedIn `url` + optional `externalId` you'll get back), `deliveryMode`, `freshness`, and a `webhookUrl` (required for `webhook`, optional for `poll`).\n\n**Immediate response (202):**\n```json\n{ \"success\": true, \"data\": { \"batchId\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\", \"accepted\": 2, \"deliveryMode\": \"webhook\", \"freshness\": \"live\", \"pollUrl\": null } }\n```\nFor `deliveryMode: poll`, `pollUrl` is `/api/v1/enrichment/contacts/bulk/{batchId}`.\n\n**Webhook payload** (POSTed to your `webhookUrl` when the batch finishes) — `person` is `null` when a profile can't be matched, otherwise a full profile:\n```json\n{\n  \"batchId\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n  \"total\": 2,\n  \"found\": 1,\n  \"results\": [\n    {\n      \"externalId\": \"crm-123\",\n      \"url\": \"https://www.linkedin.com/in/marie-dupont\",\n      \"person\": {\n        \"firstName\": \"Marie\", \"lastName\": \"Dupont\", \"name\": \"Marie Dupont\",\n        \"linkedInUrl\": \"https://www.linkedin.com/in/marie-dupont\",\n        \"linkedInId\": \"251749025\", \"linkedinSalesLink\": \"ACoAAB1a2b3c4D\",\n        \"headline\": \"Head of Sales at Lemlist\",\n        \"seniority\": \"director\", \"jobFunction\": \"sales\", \"subRole\": \"sales_management\",\n        \"industry\": \"Software Development\",\n        \"activeCompany\": \"Lemlist\", \"currentCompanyId\": 12345678,\n        \"location\": \"Paris, Île-de-France, France\", \"country\": \"FR\", \"region\": \"eu\", \"geoId\": 105015875,\n        \"photoUrl\": \"https://media.licdn.com/dms/image/abc123\",\n        \"followers\": \"4200\", \"followerCount\": 4200, \"connectionsCount\": 500,\n        \"linkedinSummary\": \"Helping outbound teams book more meetings.\",\n        \"skillsList\": \"Sales, SaaS, Team Leadership\",\n        \"skillsDetail\": [ { \"name\": \"Sales\", \"endorsements\": 42 }, { \"name\": \"SaaS\", \"endorsements\": 17 } ],\n        \"languages\": \"French, English\",\n        \"languagesDetail\": [ { \"name\": \"French\", \"proficiency\": \"native\" }, { \"name\": \"English\", \"proficiency\": \"professional\" } ],\n        \"currentCompanyDetail\": [\n          {\n            \"companyName\": \"Lemlist\", \"companyId\": 12345678, \"jobTitle\": \"Head of Sales\",\n            \"startTime\": \"2023-01-01\", \"endTime\": \"Present\",\n            \"companyUrl\": \"https://www.linkedin.com/company/lemlist\",\n            \"companyWebsite\": \"https://lemlist.com\",\n            \"companyIndustry\": \"Software Development\", \"companyStaffRange\": \"51-200\",\n            \"companyHqCity\": \"Paris\", \"companyCountryCode\": \"FR\"\n          }\n        ],\n        \"pastCompaniesDetails\": [\n          { \"companyName\": \"Acme\", \"jobTitle\": \"Account Executive\", \"startTime\": \"2020-01-01\", \"endTime\": \"2022-12-01\" }\n        ],\n        \"formerCompaniesList\": \"Acme\",\n        \"education\": {\n          \"universitiesNamesList\": \"HEC Paris\",\n          \"educationDetails\": [ { \"universityName\": \"HEC Paris\", \"degree\": \"MBA\", \"fieldsOfStudy\": [\"Marketing\"], \"startedOn\": { \"year\": \"2016\" }, \"endedOn\": { \"year\": \"2018\" } } ]\n        }\n      }\n    },\n    { \"externalId\": \"crm-456\", \"url\": \"https://www.linkedin.com/in/jean-martin\", \"person\": null }\n  ]\n}\n```\n\n**Each `person` returns:** identity (`firstName`, `lastName`, `name`, `linkedInUrl`, `linkedInId`, `linkedinSalesLink`, `photoUrl`); role (`headline`, `seniority`, `jobFunction`, `subRole`, `industry`); location (`location`, `country` + `countryName`, `region` + `regionName`, `geoId`); reach (`followers`, `followerCount`, `connectionsCount`); `linkedinSummary`; skills (`skillsList` + `skillsDetail` with endorsement counts); languages (`languages` + `languagesDetail` with proficiency); current & past positions with tenure (`yearsInRole`, `yearsInCompany`) and company firmographics (`currentCompanyDetail` / `pastCompaniesDetails` — company industry, staff range, HQ, website, …); and `education` (with degrees). Any field is `null` when the profile doesn't have it. Best coverage comes from LinkedIn profile URLs.","operationId":"enrichment_contacts_bulk_api_v1_enrichment_contacts_bulk_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"profiles":{"items":{"properties":{"url":{"type":"string","title":"Url","description":"LinkedIn profile URL to enrich"},"externalId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Externalid","description":"Your own reference for this profile — echoed back in the webhook payload"}},"type":"object","required":["url"],"title":"BulkProfileItem","description":"One profile to enrich in a bulk request.","examples":[{"externalId":"crm-123","url":"https://www.linkedin.com/in/marie-dupont"}]},"type":"array","maxItems":50000,"minItems":1,"title":"Profiles","description":"Profiles to enrich (1–50,000 per request)"},"deliveryMode":{"type":"string","enum":["webhook","poll"],"title":"Deliverymode","description":"How to receive results. `webhook` (default): the full enriched batch is POSTed to your `webhookUrl` when it completes. `poll`: results are held for you to fetch via `GET /api/v1/enrichment/contacts/bulk/{batchId}` (paginated) — nothing large is pushed; if you also pass a `webhookUrl` you get a small ready-notification when the batch finishes. **Use `poll` for requests over 5,000 profiles** so a 50,000-profile result isn't delivered in a single push.","default":"webhook"},"freshness":{"type":"string","enum":["live","cached"],"title":"Freshness","description":"Data freshness. `live` (default): a fresh scrape of each profile — most current data, full price (0.5 credits/match), and slower (large batches can take a while). `cached`: served from our directory cache — **half price (0.25 credits/match)** and much faster (typically ~1 min), at the cost of data that may be slightly less recent. Charged per successful match either way.","default":"live"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"HTTPS URL to receive results. Required for `deliveryMode: webhook` (receives the full batch). Optional for `deliveryMode: poll` (receives only a small ready-notification; omit it to poll silently)."}},"type":"object","required":["profiles"],"title":"BulkContactEnrichmentRequest","description":"Bulk contact-enrichment request (results delivered by webhook).","examples":[{"deliveryMode":"webhook","freshness":"live","profiles":[{"externalId":"crm-123","url":"https://www.linkedin.com/in/marie-dupont"},{"externalId":"crm-456","url":"https://www.linkedin.com/in/jean-martin"}],"webhookUrl":"https://your-server.com/webhooks/enrichment"}]}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"data":{"properties":{"batchId":{"type":"string","title":"Batchid","description":"Identifier for this batch, echoed in the webhook / poll response"},"accepted":{"type":"integer","title":"Accepted","description":"Number of profiles accepted for enrichment"},"deliveryMode":{"type":"string","title":"Deliverymode","description":"How results will be delivered: `webhook` or `poll`","default":"webhook"},"freshness":{"type":"string","title":"Freshness","description":"Data freshness for this batch: `live` or `cached`","default":"live"},"pollUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pollurl","description":"For `deliveryMode: poll` — the path to GET the finished batch (paginated)"}},"additionalProperties":true,"type":"object","required":["batchId","accepted"],"title":"_BulkAcceptedData"}},"type":"object","required":["data"],"title":"BulkAcceptedResponse","description":"Immediate 202 acknowledgement — results arrive later via the webhook.","examples":[{"data":{"accepted":2,"batchId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"success":true}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"profiles","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/enrichment/contacts/bulk/{batch_id}":{"get":{"tags":["Enrichment"],"summary":"Poll a bulk-enrichment batch","description":"Fetch the status and (paginated) results of a bulk-enrichment batch submitted to `POST /api/v1/enrichment/contacts/bulk`.\n\nThis is the delivery path for `deliveryMode: poll`, and a fallback for `deliveryMode: webhook` (e.g. a missed webhook). Cost is unchanged — the 0.5-credit-per-match charge happens once on completion, whether you poll or use a webhook.\n\n**Lifecycle:** `status` is `pending` → `processing` → `done` | `failed` (and, in webhook mode only, `delivery_failed` if the batch enriched fine but your webhook kept rejecting the push). Poll every few seconds while `pending`/`processing`.\n\n**Input:** `batchId` in the path. Pagination: `cursor` (opaque, start omitted) and `limit` (default 1,000, max 10,000).\n\n**Output:** `status`, `total`, `found`, and `results` — each `{externalId, url, person}` where `person` is the full profile (same shape as the webhook payload) or `null` when not matched. When more results remain, `nextCursor` is set — pass it back as `?cursor=` for the next page.\n\nResults are retained for **7 days** after completion; older or unknown batch IDs return 404.","operationId":"enrichment_contacts_bulk_get_api_v1_enrichment_contacts_bulk__batch_id__get","security":[{"BearerAuth":[]}],"parameters":[{"name":"batch_id","in":"path","required":true,"schema":{"type":"string","title":"Batch Id"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Opaque pagination cursor (start from the beginning if omitted)","default":0,"title":"Cursor"},"description":"Opaque pagination cursor (start from the beginning if omitted)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"description":"Max results per page (default 1,000)","default":1000,"title":"Limit"},"description":"Max results per page (default 1,000)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"data":{"properties":{"batchId":{"type":"string","title":"Batchid","description":"The batch identifier"},"status":{"type":"string","title":"Status","description":"`pending` | `processing` | `done` | `failed` | `delivery_failed` (`delivery_failed` only in webhook mode — the enrichment finished but your webhook kept rejecting delivery)"},"deliveryMode":{"type":"string","title":"Deliverymode","description":"`webhook` or `poll`"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Total profiles in the batch (null until done)"},"found":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Found","description":"Profiles successfully enriched (null until done)"},"results":{"items":{"properties":{"externalId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Externalid","description":"Your own reference, echoed back from the request"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"The LinkedIn profile URL that was enriched"},"person":{"anyOf":[{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline"},"linkedinSummary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinsummary","description":"The profile \"About\" section"},"photoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photourl"},"linkedInUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"linkedInId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinid","description":"LinkedIn's numeric member id"},"linkedinSalesLink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinsaleslink","description":"Sales Navigator member token for this profile"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country","description":"ISO-3166 alpha-2, e.g. `US`"},"countryName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Countryname"},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region","description":"Short region code, e.g. \"na\""},"regionName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Regionname","description":"e.g. \"North America\""},"geoId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Geoid","description":"LinkedIn's numeric location id"},"industry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Industry"},"industryId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Industryid"},"seniority":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seniority","description":"Seniority band, e.g. \"cxo\""},"subRole":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subrole","description":"Normalised role, e.g. \"chairman and ceo\""},"jobFunction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobfunction","description":"Normalised function, e.g. \"general_management\""},"activeCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Activecompany","description":"Current employer name"},"currentCompanyId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Currentcompanyid"},"currentCompanyDetail":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"jobTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitle"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Where the role was based"},"startTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime","description":"Start date (YYYY-MM-DD)"},"endTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime","description":"End date (YYYY-MM-DD), or \"Present\" for a current role"},"yearsInCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsincompany","description":"Human-readable, e.g. \"8 yrs 7 mos\""},"yearsInRole":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsinrole","description":"Human-readable, e.g. \"8 yrs 7 mos\""},"employmentStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employmentstatus"},"companyId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companyid","description":"LinkedIn's numeric company id"},"companyUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyurl","description":"Company LinkedIn page URL"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"companyIndustry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyindustry"},"companyType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companytype","description":"e.g. \"Public Company\", \"Educational Institution\""},"companyTagline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companytagline"},"companyDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companydescription"},"companySpecialties":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Companyspecialties"},"companyStaffCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companystaffcount","description":"Employees on LinkedIn"},"companyStaffRange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companystaffrange","description":"Size band, e.g. \"10001+\""},"companyFollowerCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companyfollowercount"},"companyFoundedYear":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companyfoundedyear"},"companyRevenueRange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyrevenuerange"},"companyHqCity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyhqcity"},"companyHqRegion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyhqregion"},"companyCountryCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companycountrycode","description":"ISO-3166 alpha-2, e.g. `US`"}},"additionalProperties":true,"type":"object","title":"_BulkCompanyDetail","description":"One role in a bulk-enriched profile's history.\n\nDeliberately NOT ``_PersonCompanyDetail``: verified against live responses\nfor the same profile on 2026-08-07, this block carries a full firmographic\npayload (staff count, industry, HQ, specialties) that ``GET\n/enrichment/contact`` does not return, while omitting that endpoint's\n``jobDescription``. Sharing one model would advertise fields neither\nendpoint reliably sends."},"type":"array"},{"type":"null"}],"title":"Currentcompanydetail"},"pastCompaniesDetails":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"jobTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitle"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Where the role was based"},"startTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime","description":"Start date (YYYY-MM-DD)"},"endTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime","description":"End date (YYYY-MM-DD), or \"Present\" for a current role"},"yearsInCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsincompany","description":"Human-readable, e.g. \"8 yrs 7 mos\""},"yearsInRole":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsinrole","description":"Human-readable, e.g. \"8 yrs 7 mos\""},"employmentStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employmentstatus"},"companyId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companyid","description":"LinkedIn's numeric company id"},"companyUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyurl","description":"Company LinkedIn page URL"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"companyIndustry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyindustry"},"companyType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companytype","description":"e.g. \"Public Company\", \"Educational Institution\""},"companyTagline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companytagline"},"companyDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companydescription"},"companySpecialties":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Companyspecialties"},"companyStaffCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companystaffcount","description":"Employees on LinkedIn"},"companyStaffRange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companystaffrange","description":"Size band, e.g. \"10001+\""},"companyFollowerCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companyfollowercount"},"companyFoundedYear":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Companyfoundedyear"},"companyRevenueRange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyrevenuerange"},"companyHqCity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyhqcity"},"companyHqRegion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyhqregion"},"companyCountryCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companycountrycode","description":"ISO-3166 alpha-2, e.g. `US`"}},"additionalProperties":true,"type":"object","title":"_BulkCompanyDetail","description":"One role in a bulk-enriched profile's history.\n\nDeliberately NOT ``_PersonCompanyDetail``: verified against live responses\nfor the same profile on 2026-08-07, this block carries a full firmographic\npayload (staff count, industry, HQ, specialties) that ``GET\n/enrichment/contact`` does not return, while omitting that endpoint's\n``jobDescription``. Sharing one model would advertise fields neither\nendpoint reliably sends."},"type":"array"},{"type":"null"}],"title":"Pastcompaniesdetails"},"formerCompaniesList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Formercompanieslist","description":"Previous employers, comma-separated"},"education":{"anyOf":[{"properties":{"educationDetails":{"anyOf":[{"items":{"properties":{"universityName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universityname"},"degree":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Degree"},"fieldsOfStudy":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Fieldsofstudy"},"schoolId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Schoolid","description":"LinkedIn's numeric id for the school"},"startedOn":{"anyOf":[{"properties":{"year":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Year"}},"additionalProperties":true,"type":"object","title":"_PersonEducationYear"},{"type":"null"}]},"endedOn":{"anyOf":[{"properties":{"year":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Year"}},"additionalProperties":true,"type":"object","title":"_PersonEducationYear"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_BulkEducationDetail","description":"One school in a bulk-enriched profile."},"type":"array"},{"type":"null"}],"title":"Educationdetails"},"universitiesNamesList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universitiesnameslist","description":"All school names, comma-separated — convenient for a single CRM field"}},"additionalProperties":true,"type":"object","title":"_BulkEducation"},{"type":"null"}]},"connectionsCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Connectionscount"},"followerCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Followercount"},"followers":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Followers","description":"Same value as `followerCount`, as a string"},"languages":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Languages","description":"Languages, comma-separated"},"languagesDetail":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Languagesdetail","description":"Per-language entries. Left free-form on purpose: it was `null` on every profile we probed against live production (2026-08-07), so we have no observed shape to publish. Read defensively."},"skillsList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skillslist","description":"Skills, comma-separated"},"skillsDetail":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Skillsdetail","description":"Per-skill entries. Free-form for the same reason as `languagesDetail` — never observed populated."}},"additionalProperties":true,"type":"object","title":"_BulkPerson","description":"A bulk-enriched profile.\n\nTyped from live responses on 2026-08-07 rather than from the sibling\n``GET /enrichment/contact`` model: for the SAME profile the two endpoints\nreturn materially different objects (bulk adds seniority/jobFunction/geo\nids, contact adds isPremium/city/websites and 15 more). Generating one\ntype for both would misdescribe whichever you called."},{"type":"null"}],"description":"Enriched person — the same object the bulk webhook delivers. Null when the profile could not be matched (expect this for a minority of URLs in any batch, so guard before reading it). Note this is a different, richer shape than `GET /enrichment/contact` returns for the same profile — see the field list rather than assuming the two match."}},"additionalProperties":true,"type":"object","title":"_BulkResultItem","description":"One enriched profile in a bulk batch page.\n\nWas ``items: {}`` until 2026-08-06, so generated clients could not type the\npage at all. ``person`` is the same shape the bulk webhook delivers, and is\nnull when the profile could not be matched."},"type":"array","title":"Results","description":"This page of results — each `{externalId, url, person}` (same `person` shape as the webhook payload; `person` is null when not matched). Empty until the batch is `done`."},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nextcursor","description":"Pass as `?cursor=` to fetch the next page; null when no more"}},"additionalProperties":true,"type":"object","required":["batchId","status","deliveryMode"],"title":"_BulkBatchStatusData"}},"type":"object","required":["data"],"title":"BulkBatchStatusResponse","description":"Status + (paginated) results of a bulk-enrichment batch.","examples":[{"data":{"batchId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","deliveryMode":"poll","found":1,"results":[{"externalId":"crm-123","person":{"firstName":"Marie","headline":"Head of Sales at Lemlist","lastName":"Dupont","linkedInUrl":"https://www.linkedin.com/in/marie-dupont","name":"Marie Dupont"},"url":"https://www.linkedin.com/in/marie-dupont"},{"externalId":"crm-456","url":"https://www.linkedin.com/in/jean-martin"}],"status":"done","total":2},"success":true}]}}}},"404":{"description":"No batch found for this ID under your account — wrong ID, results aged out (7-day TTL), or the ID belongs to a different account.","content":{"application/json":{"example":{"detail":"Not found."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"batch_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/financial":{"get":{"tags":["Enrichment"],"summary":"Get company financial data","description":"Understand a company's funding trajectory, capitalization status (public vs. private), and acquisition history—essential for deal qualification, competitive research, and prospect scoring.\n\n**Input** (at least one required): company domain (`domain`), name (`companyName`), LinkedIn company URL (`companyLinkedinUrl`), or French business IDs (`siren`/`siret`).\n\n**Output:** funding round history (total raised USD, round count, latest round type & date, investor list); IPO status with stock symbol and go-public date if public; acquisition activity (whether the company has been acquired or has made acquisitions, with a count); founding year; founder names; headquarters location; employee count range; industry categories; operating status.","operationId":"enrichment_financial_api_v1_enrichment_financial_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company domain (e.g. google.com)","title":"Domain"},"description":"Company domain (e.g. google.com)"},{"name":"siren","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"SIREN number (9 digits)","title":"Siren"},"description":"SIREN number (9 digits)"},{"name":"siret","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"SIRET number (14 digits)","title":"Siret"},"description":"SIRET number (14 digits)"},{"name":"companyName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company name","title":"Companyname"},"description":"Company name"},{"name":"companyLinkedinUrl","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company LinkedIn URL","title":"Companylinkedinurl"},"description":"Company LinkedIn URL"}],"responses":{"200":{"description":"Company financials (`data.data`).","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Result status, one of: success, error, not_found"},"data":{"anyOf":[{"properties":{"company_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"founded_on":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Founded On","description":"Founding date, ISO-8601 (YYYY-MM-DD)"},"operating_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operating Status","description":"Operating status, one of: active, closed"},"num_employees_enum":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Num Employees Enum","description":"Employee count range, one of: Self-employed, 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+"},"funding":{"anyOf":[{"properties":{"total_funding_amount_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Funding Amount Usd"},"funding_total_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Funding Total Currency","description":"ISO-4217 currency code"},"funding_total_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Funding Total Value"},"num_funding_rounds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Funding Rounds"},"last_funding_total_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Last Funding Total Usd"},"last_round":{"anyOf":[{"properties":{"amount_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount Currency","description":"ISO-4217 currency code, e.g. \"USD\""},"amount_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amount Value","description":"Amount raised in the last round"},"num_investors":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Investors"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"Funding round type, one of: bootstrapped, pre_seed, seed, angel, series_a, series_b, series_c, series_d, series_e, grant, debt_financing, convertible_note, private_equity, post_ipo_equity, corporate_round, undisclosed"}},"additionalProperties":true,"type":"object","title":"_FinancialLastRound"},{"type":"null"}]},"num_investors":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Investors"},"last_funding_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Funding Type","description":"Type of the most recent round, one of: bootstrapped, pre_seed, seed, angel, series_a, series_b, series_c, series_d, series_e, grant, debt_financing, convertible_note, private_equity, post_ipo_equity, corporate_round, undisclosed"},"latest_funding_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Latest Funding Date","description":"Date of the most recent round"},"investors":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Investors","description":"List of known investors"}},"additionalProperties":true,"type":"object","title":"_FinancialFunding"},{"type":"null"}]},"ipo":{"anyOf":[{"properties":{"ipo_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ipo Status","description":"IPO status, one of: private, public, delisted"},"stock_symbol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stock Symbol"},"stock_exchange_symbol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stock Exchange Symbol"},"went_public_on":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Went Public On","description":"IPO date, ISO-8601 or empty string"},"ipo_valuation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ipo Valuation"},"ipo_amount_raised":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ipo Amount Raised"}},"additionalProperties":true,"type":"object","title":"_FinancialIpo"},{"type":"null"}]},"categories":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Categories","description":"Industry/category tags"},"headquarters_location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headquarters Location","description":"Comma-separated HQ location (city,state,country,region)"},"founders":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Founders"},"contact_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Email"},"acquisitions":{"anyOf":[{"properties":{"acquisition_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acquisition Status","description":"Acquisition status, one of: no_acquisitions, made_acquisitions, was_acquired"},"num_acquisitions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Acquisitions"}},"additionalProperties":true,"type":"object","title":"_FinancialAcquisitions"},{"type":"null"}]},"revenue_metrics":{"anyOf":[{"properties":{},"additionalProperties":true,"type":"object","title":"_FinancialRevenueMetrics","description":"Free-form revenue block from our funding data.\n\nDeliberately untyped: we have never observed it populated. Probed against\nlive production on 2026-08-07 across companies of very different profiles\n(Qonto, Doctolib, BlaBlaCar, Datadog, Stripe) and it was ``null`` every\ntime. Rather than invent a shape that no consumer could rely on, we say so in the field description — see the note there."},{"type":"null"}],"description":"Reserved. In practice this is always `null` — treat it as absent and do not build against it. If it ever carries data the contents are free-form, so read it defensively rather than typing it."}},"additionalProperties":true,"type":"object","title":"_FinancialCompanyData"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_FinancialData"},{"type":"null"}],"description":"Financial payload, or null if the company was not found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"FinancialResponse","description":"Typed response for the company financial endpoint."},"example":{"data":{"status":"success","data":{"company_name":"Lemlist","description":"Lemlist is a sales engagement platform for outbound teams.","website":"https://lemlist.com","domain":"lemlist.com","founded_on":"2018-01-01","operating_status":"active","num_employees_enum":"51-200","funding":{"total_funding_amount_usd":0,"funding_total_currency":"USD","funding_total_value":0,"num_funding_rounds":1,"last_funding_total_usd":0,"last_round":{"amount_currency":"","amount_value":0,"num_investors":0,"type":"bootstrapped"},"num_investors":0,"last_funding_type":"bootstrapped","latest_funding_date":"","investors":[]},"ipo":{"ipo_status":"private","stock_symbol":"","stock_exchange_symbol":"","went_public_on":""},"categories":["SaaS","Sales","Email"],"headquarters_location":"Paris,Île-de-France,France,Europe","founders":["Guillaume Moubeche"],"contact_email":"hello@lemlist.com","acquisitions":{"acquisition_status":"no_acquisitions","num_acquisitions":0}}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/find-email":{"get":{"tags":["Enrichment"],"summary":"Find an email address","description":"Find a professional email address for a person from their name and company, with deliverability validation. Useful for lead research and prospecting.\n\n**Input:** `firstName` + `lastName` (or `fullName`), plus a company identifier — `companyName` or `domain`. At least one identifier is required; supplying the person's name together with a company yields the best match rate. Any missing identifiers are automatically completed from your account data to improve accuracy.\n\n**Output:** `email` (the address, or null when none found), `emailDomain`, `status` (deliverability — one of Valid, Invalid, Unknown, Accept-all, Risky), `smtpCheck` (boolean SMTP verification result), `mxfound` (boolean — whether an MX record exists for the domain), `patterns` (detected address formats such as `{first}.{last}@domain.com`), `mostProbableEmail` (ranked alternative candidates, empty when none), `flags` (deliverability risk flags), `mxRecord` (primary MX host), and `smtpProvider` (mail host — `google`, `microsoft`, or `other`).","operationId":"enrichment_find_email_api_v1_enrichment_find_email_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"firstName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"First name","title":"Firstname"},"description":"First name"},{"name":"lastName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Last name","title":"Lastname"},"description":"Last name"},{"name":"fullName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full name","title":"Fullname"},"description":"Full name"},{"name":"companyName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company name","title":"Companyname"},"description":"Company name"},{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company domain (e.g. google.com)","title":"Domain"},"description":"Company domain (e.g. google.com)"}],"responses":{"200":{"description":"Found email with deliverability status.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Found email address, or null if none found"},"emailDomain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emaildomain"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Deliverability status — one of: Valid, Invalid, Unknown, Accept-all, Risky"},"smtpCheck":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Smtpcheck","description":"Whether the SMTP verification passed"},"mxfound":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Mxfound","description":"Whether an MX record was found for the domain"},"patterns":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Patterns","description":"Detected email patterns, e.g. {first}.{last}@domain.com"},"mostProbableEmail":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Mostprobableemail","description":"Ranked alternative email candidates (empty when none)"},"flags":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Flags","description":"Deliverability risk flags (empty when none)"},"mxRecord":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mxrecord","description":"Primary MX record host for the domain"},"smtpProvider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Smtpprovider","description":"Mail host behind the domain, e.g. \"google\", \"microsoft\", \"other\""}},"additionalProperties":true,"type":"object","title":"_FindEmailData","description":"``data`` payload for the sync find-email endpoint."},{"type":"null"}],"description":"Email lookup result, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"FindEmailResponse","description":"Typed response for ``GET /enrichment/find-email``."},"example":{"data":{"email":"marie.dupont@lemlist.com","emailDomain":"lemlist.com","status":"Valid","smtpCheck":true,"mxfound":true,"patterns":["{first}.{last}@lemlist.com"],"mostProbableEmail":[],"flags":[],"mxRecord":"aspmx.l.google.com","smtpProvider":"google"},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}},"post":{"tags":["Enrichment"],"summary":"Find an email — async, deep resolution","description":"Find an email address for a person at a company through a comprehensive, multi-source resolution that runs deeper than a single-source lookup—submit your request and poll for the result, which typically resolves within 10–60 seconds for a higher hit rate.\n\n**Input:** person name (`firstName` + `lastName`, or `fullName` as a fallback) plus, for best results, at least one supporting identifier — `companyName`, `domain`, `contactLinkedinUrl`, or `companyLinkedinUrl`.\n\n**Output:** the submit call returns a `requestId`, a `statusUrl`, and an `expiresAt` timestamp immediately. Poll the status endpoint to retrieve the resolved email address (or `null` if no deliverable email is found), the `status` (`pending` / `completed` / `failed`), billing info (`creditsCharged`: 0.5 on success, 0 otherwise), and `createdAt` / `completedAt` timestamps. Requests are stored for 24 hours.","operationId":"submit_find_email_api_v1_enrichment_find_email_post","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"fullName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fullname"},"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"contactLinkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contactlinkedinurl"},"companyLinkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylinkedinurl"}},"type":"object","title":"FindEmailSubmit","description":"Body for POST ``/enrichment/find-email``. Identical identifier\nsurface as the GET, just as JSON instead of query params.\n\nProvide ``firstName`` + ``lastName`` plus at least one of\n``companyName`` / ``domain`` / ``contactLinkedinUrl`` /\n``companyLinkedinUrl`` for best results. ``fullName`` is accepted\nas a fallback when the first/last split isn't available.","examples":[{"companyLinkedinUrl":"https://linkedin.com/company/lemlist","companyName":"Lemlist","contactLinkedinUrl":"https://linkedin.com/in/mariedupont","domain":"lemlist.com","firstName":"Marie","lastName":"Dupont"}]}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"requestId":{"type":"string","title":"Requestid"},"status":{"type":"string","title":"Status","description":"Always ``'pending'`` on submit. Poll the status URL.","default":"pending"},"statusUrl":{"type":"string","title":"Statusurl"},"expiresAt":{"type":"string","title":"Expiresat"}},"type":"object","required":["requestId","statusUrl","expiresAt"],"title":"FindEmailSubmitResponse","description":"Response for POST ``/enrichment/find-email``.","examples":[{"expiresAt":"2026-06-01T14:30:00+00:00","requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","status":"pending","statusUrl":"/api/v1/enrichment/find-email/status/a1b2c3d4-e5f6-7890-abcd-ef1234567890"}]}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/find-email/status/{request_id}":{"get":{"tags":["Enrichment"],"summary":"Poll an async find-email request","description":"Check your async email-finding request and retrieve the found email address when it's ready.\n\n**Input:** `requestId` (the unique ID returned when you submitted the email-finding request via POST)\n\n**Output:** The current `status` (`'pending'` while resolving, `'completed'` when resolution finished, or `'failed'` on an internal error — retry the POST), the discovered `email` address (or `null` if resolution finished without finding a deliverable email), `errorMessage` (a reason string when `status` is `'failed'`, otherwise `null`), `creditsCharged` (0.5 credits on success, 0 otherwise), and timestamps (`createdAt`, `completedAt`) showing when the request was submitted and when resolution finished. Results are retained for 24 hours after submission.","operationId":"get_find_email_status_api_v1_enrichment_find_email_status__request_id__get","security":[{"BearerAuth":[]}],"parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"requestId":{"type":"string","title":"Requestid"},"status":{"type":"string","title":"Status","description":"``'pending'`` (still resolving), ``'completed'`` (resolution finished — check ``email`` for the result), or ``'failed'`` (internal error, retry the POST)."},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"The deliverable email, or null when resolution finished without finding one."},"errorMessage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Errormessage","description":"Reason when ``status`` is ``'failed'``"},"creditsCharged":{"type":"number","title":"Creditscharged","description":"Credits deducted — 0.5 on success, 0 otherwise","default":0.0},"createdAt":{"type":"string","title":"Createdat"},"completedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completedat"}},"type":"object","required":["requestId","status","createdAt"],"title":"FindEmailStatusResponse","description":"Response for GET ``/enrichment/find-email/status/{request_id}``.","examples":[{"completedAt":"2026-05-31T14:30:42+00:00","createdAt":"2026-05-31T14:30:00+00:00","creditsCharged":0.5,"email":"marie.dupont@lemlist.com","requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","status":"completed"}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"request_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/firmographic":{"get":{"tags":["Enrichment"],"summary":"Get company firmographic data","description":"Enrich your database with company intelligence — find out company size, industry, location, specialties, and key details by domain, company name, or LinkedIn URL.\n\n**Input:** one or more company identifiers (`domain`, `companyName`, `companyLinkedinUrl`).\n\n**Output:** structured company data (`data.company.firmographics`) including name, website, LinkedIn URL, employee count range, industry, specialties, headquarters location and postal details, founding year, company description, logo URL, and all known office locations. Returned synchronously in a single request.","operationId":"enrichment_firmographic_api_v1_enrichment_firmographic_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company domain (e.g. google.com)","title":"Domain"},"description":"Company domain (e.g. google.com)"},{"name":"companyName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company name","title":"Companyname"},"description":"Company name"},{"name":"companyLinkedinUrl","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company LinkedIn URL","title":"Companylinkedinurl"},"description":"Company LinkedIn URL"}],"responses":{"200":{"description":"Company firmographics (`data.company.firmographics`).","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"company":{"anyOf":[{"properties":{"companySearch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companysearch","description":"The lookup value that was resolved (domain, name, or URL)"},"firmographics":{"anyOf":[{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"industries":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Industries","description":"Primary industry classification"},"specialties":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Specialties","description":"Comma-separated list of specialties"},"specialtiesList":{"anyOf":[{"items":{"properties":{"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value"}},"additionalProperties":true,"type":"object","title":"_FirmographicSpecialty","description":"One specialty, wrapped as ``{value: ...}``.\n\nKept as-is rather than flattened to ``string[]``: the field is a passthrough\nand unwrapping it would silently change the shape for every existing\nconsumer. Clients that prefer a flat list should map ``.value``."},"type":"array"},{"type":"null"}],"title":"Specialtieslist","description":"List of specialty objects, each {\"value\": <str>}. The wrapper is intentional and stable — map `.value` if you want a flat string list."},"companySize":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companysize","description":"Employee count range, one of: Self-employed, 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+"},"employeesNumLinkedin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employeesnumlinkedin","description":"Reported employee count as a string"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"Company type, one of: Privately Held, Public Company, Non Profit, Government Agency, Partnership, Self-Employed, Self-Owned, Educational Institution"},"founded":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Founded","description":"Founding year, e.g. \"2018\""},"headquarters":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headquarters","description":"Full HQ address on one line"},"countryCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Countrycode","description":"ISO-3166 alpha-2 country code, e.g. \"FR\""},"HQcity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hqcity"},"HQcountry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hqcountry"},"HQstate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hqstate"},"HQpostalCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hqpostalcode"},"additionalInfo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Additionalinfo"},"countriesImplementation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Countriesimplementation","description":"Comma-separated country codes where the company operates"},"aboutUs":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aboutus","description":"Company description"},"slogan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slogan","description":"Company tagline"},"socialFollowers":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Socialfollowers","description":"Social follower count"},"imageUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Imageurl","description":"Company logo URL"},"locations":{"anyOf":[{"items":{"properties":{"State":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"City":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"Street":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Street"},"PostalCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postalcode"},"AdditionalInfo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Additionalinfo"},"Description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Office label, e.g. \"Headquarters\", \"Office\""},"Headquarter":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Headquarter","description":"True if this location is the head office"}},"additionalProperties":true,"type":"object","title":"_FirmographicLocation"},"type":"array"},{"type":"null"}],"title":"Locations","description":"All known office locations"},"HQphoneNumber":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hqphonenumber","description":"Head-office phone number, **always a string** — `\"\"` when the company has none. An extension, when the source provides one, is appended as `\"01 23 45 67 89 ext. 12\"`. Until 2026-08-11 this field returned a raw object for companies that had a phone and an empty string for those that did not, so its type varied with the data; it is now flattened."},"linkedinId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinid","description":"Numeric LinkedIn company identifier"},"numberOfLocation":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Numberoflocation","description":"Count of known office locations"},"crunchbaseUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Funding Profile URL","description":"Public funding-profile URL for the company, when known"}},"additionalProperties":true,"type":"object","title":"_FirmographicFirmographics"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_FirmographicCompany"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_FirmographicData"},{"type":"null"}],"description":"Firmographic payload, or null if the company was not found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"FirmographicResponse","description":"Typed response for the company firmographic endpoint."},"example":{"data":{"company":{"companySearch":"lemlist.com","firmographics":{"name":"Lemlist","website":"lemlist.com","linkedinUrl":"https://www.linkedin.com/company/lemlist/","industries":"Software Development","specialties":"Cold email, Sales engagement, Outbound","specialtiesList":["Cold email","Sales engagement","Outbound"],"companySize":"51-200","employeesNumLinkedin":"142","type":"Privately Held","founded":"2018","headquarters":"Paris Île-de-France France","countryCode":"FR","HQcity":"Paris","HQcountry":"France","HQstate":"Île-de-France","HQpostalCode":"75002","additionalInfo":"","countriesImplementation":"FR","aboutUs":"Lemlist is a sales engagement platform that helps teams start conversations that get replies.","slogan":"Start conversations that get replies","socialFollowers":38214,"imageUrl":"https://media.licdn.com/dms/image/v2/example/company-logo_200_200/0/1700000000000","locations":[{"State":"Île-de-France","City":"Paris","Street":"24 Rue du Sentier","PostalCode":"75002","AdditionalInfo":"","Description":"Headquarters","Headquarter":true}]}}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/french-sirene":{"get":{"tags":["Enrichment"],"summary":"Look up French SIRENE data","description":"Verify the legal identity and official status of French companies by pulling authoritative registration data from the government SIRENE registry.\n\n**Input:** At least one of: `siren` (9-digit government ID), `siret` (14-digit establishment ID), `domain` (website), `companyName`, or `companyLinkedinUrl`.\n\n**Output:** `data.frenchCompany` returns the official SIRENE record with company legal name and form (`nom_complet`, `nature_juridique`), size category (`categorie_entreprise`), administrative status (`etat_administratif`: A=active/C=closed), founding and closure dates, NAF activity codes (`activite_principale`), employee count band (`tranche_effectif_salarie`), headquarters address with parsed street components and GPS coordinates, list of company officers with roles and birth years, compliance flags (non-profit status, public service, etc.), and financial figures when published. All fields follow the official SIRENE schema and return null if the registry has no value.","operationId":"enrichment_french_sirene_api_v1_enrichment_french_sirene_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"siren","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"SIREN number (9 digits)","title":"Siren"},"description":"SIREN number (9 digits)"},{"name":"siret","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"SIRET number (14 digits)","title":"Siret"},"description":"SIRET number (14 digits)"},{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company domain (e.g. google.com)","title":"Domain"},"description":"Company domain (e.g. google.com)"},{"name":"companyName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company name","title":"Companyname"},"description":"Company name"},{"name":"companyLinkedinUrl","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company LinkedIn URL","title":"Companylinkedinurl"},"description":"Company LinkedIn URL"}],"responses":{"200":{"description":"Official French registry record (`data.frenchCompany`).","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"frenchCompany":{"anyOf":[{"properties":{"siren":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Siren","description":"9-digit company identifier"},"nom_complet":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nom Complet"},"nom_raison_sociale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nom Raison Sociale"},"sigle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sigle"},"date_creation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Creation","description":"Creation date, ISO-8601 (YYYY-MM-DD)"},"date_fermeture":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Fermeture","description":"Closure date, ISO-8601 or null"},"etat_administratif":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Etat Administratif","description":"Administrative state, one of: A (active), C (closed)"},"statut_diffusion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Statut Diffusion","description":"Diffusion status, one of: O (public), P (partially protected)"},"nature_juridique":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nature Juridique","description":"INSEE legal-form code (catégorie juridique), e.g. \"5710\""},"activite_principale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Activite Principale","description":"NAF/APE activity code, e.g. \"62.01Z\""},"activite_principale_naf25":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Activite Principale Naf25","description":"NAF 2025 activity code"},"section_activite_principale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Section Activite Principale","description":"NAF section letter, one of: A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U"},"categorie_entreprise":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Categorie Entreprise","description":"Company size category, one of: PME, ETI, GE"},"annee_categorie_entreprise":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Annee Categorie Entreprise"},"tranche_effectif_salarie":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tranche Effectif Salarie","description":"INSEE employee-range code, one of: NN, 00, 01, 02, 03, 11, 12, 21, 22, 31, 32, 41, 42, 51, 52, 53"},"caractere_employeur":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Caractere Employeur","description":"Employer flag, one of: O (yes), N (no)"},"nombre_etablissements":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Nombre Etablissements"},"nombre_etablissements_ouverts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Nombre Etablissements Ouverts"},"date_mise_a_jour":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Mise A Jour","description":"Last update timestamp, ISO-8601"},"siege":{"anyOf":[{"properties":{"siret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Siret","description":"14-digit establishment identifier"},"est_siege":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Est Siege","description":"True if this is the head office"},"adresse":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Adresse","description":"Full address on one line"},"numero_voie":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Numero Voie"},"type_voie":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type Voie"},"libelle_voie":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Libelle Voie"},"code_postal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Postal"},"commune":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commune","description":"INSEE commune code"},"libelle_commune":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Libelle Commune"},"departement":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Departement"},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region"},"latitude":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Longitude"},"activite_principale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Activite Principale","description":"NAF/APE activity code, e.g. \"62.01Z\""},"etat_administratif":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Etat Administratif","description":"Administrative state, one of: A (active), F (closed)"},"date_creation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Creation","description":"Creation date, ISO-8601 (YYYY-MM-DD)"}},"additionalProperties":true,"type":"object","title":"_SireneSiege","description":"Head-office establishment of the French company."},{"type":"null"}]},"dirigeants":{"anyOf":[{"items":{"properties":{"nom":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nom"},"prenoms":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prenoms"},"qualite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Qualite","description":"Role, e.g. \"Président de SAS\", \"Gérant\""},"type_dirigeant":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type Dirigeant","description":"Officer type, one of: personne physique, personne morale"},"annee_de_naissance":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Annee De Naissance"},"nationalite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nationalite"}},"additionalProperties":true,"type":"object","title":"_SireneDirigeant"},"type":"array"},{"type":"null"}],"title":"Dirigeants","description":"Company officers / directors"},"finances":{"anyOf":[{"additionalProperties":{"properties":{"ca":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ca","description":"Revenue for the year (chiffre d'affaires), in euros"},"resultat_net":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Resultat Net","description":"Net income for the year, in euros; negative when the company made a loss"}},"additionalProperties":true,"type":"object","title":"_SireneFinanceYear","description":"One published financial year.\n\nAmounts are in euros. Shape confirmed against a live response\n(2026-08-07): ``{\"2019\": {\"ca\": 170544, \"resultat_net\": -30084}}``."},"type":"object"},{"type":"null"}],"title":"Finances","description":"Published annual accounts, keyed by four-digit year (e.g. `2019`). Only years the company actually filed appear, so the object may hold one year, several, or be `null` when nothing is published — most small companies publish nothing."},"complements":{"anyOf":[{"properties":{"est_ess":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Est Ess","description":"Social and solidarity economy flag"},"est_association":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Est Association"},"est_qualiopi":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Est Qualiopi"},"est_entrepreneur_individuel":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Est Entrepreneur Individuel"},"est_service_public":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Est Service Public"},"convention_collective_renseignee":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Convention Collective Renseignee"}},"additionalProperties":true,"type":"object","title":"_SireneComplements"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_SireneFrenchCompany"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_SireneData"},{"type":"null"}],"description":"Registry payload, or null if the company was not found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"FrenchSireneResponse","description":"Typed response for the official French registry endpoint."},"example":{"data":{"frenchCompany":{"siren":"823475082","nom_complet":"LEMLIST","nom_raison_sociale":"LEMLIST","date_creation":"2016-09-01","etat_administratif":"A","statut_diffusion":"O","nature_juridique":"5710","activite_principale":"62.01Z","activite_principale_naf25":"62.01A","section_activite_principale":"J","categorie_entreprise":"PME","annee_categorie_entreprise":"2024","tranche_effectif_salarie":"21","caractere_employeur":"O","nombre_etablissements":2,"nombre_etablissements_ouverts":1,"date_mise_a_jour":"2026-05-21T12:14:05","siege":{"siret":"82347508200018","est_siege":true,"adresse":"24 RUE DU SENTIER 75002 PARIS","numero_voie":"24","type_voie":"RUE","libelle_voie":"DU SENTIER","code_postal":"75002","commune":"75102","libelle_commune":"PARIS","departement":"75","region":"11","latitude":"48.868","longitude":"2.347","activite_principale":"62.01Z","etat_administratif":"A","date_creation":"2016-09-01"},"dirigeants":[{"nom":"MOUBECHE","prenoms":"GUILLAUME","qualite":"Président de SAS","type_dirigeant":"personne physique","annee_de_naissance":"1991"}],"finances":{"2019":{"ca":170544,"resultat_net":-30084}},"complements":{"est_ess":false,"est_association":false,"est_qualiopi":false,"est_entrepreneur_individuel":false,"est_service_public":false,"convention_collective_renseignee":false}}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/homepage-content":{"get":{"tags":["Enrichment"],"summary":"Get webpage content","description":"Fetch and parse any public webpage into clean, machine-readable markdown — ideal for researching competitor sites, analyzing landing page positioning, or extracting job descriptions to understand company messaging and hiring intent.\n\n**Input:** the page URL, path, or domain to fetch (`domain`, e.g. `google.com`, `rodz.io/blog`, `https://example.com/page`), optionally paired with the company's LinkedIn profile URL (`companyLinkedinUrl`) to improve context.\n\n**Output:** `websiteHomepage` contains the page rendered as markdown, beginning with a `Title:` line and a `URL Source:` line, followed by the parsed `Markdown Content:` body (headings, links, and text preserved); `null` when the page cannot be accessed.","operationId":"enrichment_homepage_content_api_v1_enrichment_homepage_content_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"query","required":true,"schema":{"type":"string","description":"Domain, path, or full URL to scrape (e.g. google.com, rodz.io/blog, https://example.com/page)","title":"Domain"},"description":"Domain, path, or full URL to scrape (e.g. google.com, rodz.io/blog, https://example.com/page)"},{"name":"companyLinkedinUrl","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company LinkedIn URL","title":"Companylinkedinurl"},"description":"Company LinkedIn URL"}],"responses":{"200":{"description":"Parsed page content.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"websiteHomepage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Websitehomepage","description":"Parsed homepage content as Markdown text, prefixed with a 'Title:' and 'URL Source:' header block followed by the 'Markdown Content:' body"}},"additionalProperties":true,"type":"object","title":"_HomepageContentData"},{"type":"null"}],"description":"Homepage content payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"HomepageContentResponse","description":"Typed response for the homepage-content enrichment endpoint."},"example":{"data":{"websiteHomepage":"Title: lemlist - Sales engagement platform\n\nURL Source: https://lemlist.com/\n\nMarkdown Content:\n## Start conversations that get replies\n\nlemlist helps outbound teams find leads, write personalized campaigns, and book more meetings — all from one place.\n\n[Start free](https://app.lemlist.com/signup)\n\n## Trusted by 37,000+ teams worldwide"},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"domain","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/job-location-id":{"get":{"tags":["Enrichment"],"summary":"Resolve a job location ID","description":"Find the location ID for any city, region, or country to filter company job listings by geography — quickly resolve location names without guessing or hardcoding IDs.\n\n**Input:** `name` (required) — a location name or partial match, e.g. `'Paris'`, `'Île-de-France'`, `'France'`, `'Texas'`.\n\n**Note:** this endpoint relays the job-data source's own response verbatim, which is why its fields are snake_case (`nb_results`, `full_name`) while the rest of the API is camelCase — the 1:1 correspondence lets you cross-reference ids and names against that source. **Output:** A `data` object containing `nb_results` (the count of matches) and `results`, an array of matching locations. Each result has an integer `id` (pass this as a value in the company-jobs endpoint's `locationIds` filter), plus `name`, `full_name`, `country`, `region`, and `type` (location granularity, e.g. `\"city\"` or `\"region\"`). Cost: Free.","operationId":"enrichment_locations_api_v1_enrichment_job_location_id_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","description":"Location name to search (e.g. 'Paris', 'France')","title":"Name"},"description":"Location name to search (e.g. 'Paris', 'France')"}],"responses":{"200":{"description":"Matching job locations.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"nb_results":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Nb Results","description":"Number of matching locations returned"},"results":{"anyOf":[{"items":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Id","description":"Numeric location identifier"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Short location name, e.g. 'Paris (France)'"},"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name","description":"Fully qualified location name"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country","description":"Country name"},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region","description":"Region / administrative area name"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"Location granularity, e.g. one of: city, region, country"}},"additionalProperties":true,"type":"object","title":"_JobLocationResult"},"type":"array"},{"type":"null"}],"title":"Results","description":"Matching locations"}},"additionalProperties":true,"type":"object","title":"_JobLocationData"},{"type":"null"}],"description":"Location lookup payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"JobLocationIdResponse","description":"Typed response for /enrichment/job-location-id."},"example":{"data":{"nb_results":10,"results":[{"id":2988507,"name":"Paris (France)","full_name":"Paris (France)","country":"France","region":"Ile-de-France","type":"city"},{"id":12808653,"name":"Paris 10e Arrondissement (France)","full_name":"Paris 10e Arrondissement (France)","country":"France","region":"Ile-de-France","type":"city"}]},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/linkedin-geo-id":{"get":{"tags":["Enrichment"],"summary":"Resolve a location to geo ID","description":"Convert location names into LinkedIn geo IDs for precise geographic filtering in people-search queries — target talent, decision-makers, or prospects in specific cities, regions, or countries.\n\n**Input:** `search` — the location name to resolve (e.g. 'Paris', 'California', 'France', 'Greater Boston').\n\n**Output:** `data.elements` — an array of matching LinkedIn locations, each with a `geoId` (pass to people-search's `geoIds` parameter) and a human-readable `title` (e.g. 'Paris, Île-de-France, France'). Results are ordered by relevance; the first match is usually the best fit. A name that spans several LinkedIn locations — a former French region such as 'Alsace' — returns one element per location (Bas-Rhin, Haut-Rhin): pass every `geoId` to cover the whole area. Free endpoint — no credits required.","operationId":"enrichment_geo_id_api_v1_enrichment_linkedin_geo_id_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"search","in":"query","required":true,"schema":{"type":"string","description":"Location name to resolve (e.g. 'Paris', 'California', 'Germany')","title":"Search"},"description":"Location name to resolve (e.g. 'Paris', 'California', 'Germany')"}],"responses":{"200":{"description":"Matching LinkedIn locations.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"elements":{"anyOf":[{"items":{"properties":{"geoId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Geoid","description":"LinkedIn geo identifier, usable as a geoIds filter value"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Human-readable location label, e.g. 'Paris, Île-de-France, France'"}},"additionalProperties":true,"type":"object","title":"_GeoIdElement"},"type":"array"},{"type":"null"}],"title":"Elements","description":"Matching LinkedIn locations, ordered by relevance"}},"additionalProperties":true,"type":"object","title":"_GeoIdData"},{"type":"null"}],"description":"Geo-ID lookup payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"LinkedinGeoIdResponse","description":"Typed response for the linkedin-geo-id resolution endpoint."},"example":{"data":{"elements":[{"geoId":"106383538","title":"Paris, Île-de-France, France"},{"geoId":"90009659","title":"Greater Paris Metropolitan Region"},{"geoId":"106288977","title":"Paris, Texas, United States"}]},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"search","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/linkedin-industries":{"get":{"tags":["Enrichment"],"summary":"Look up LinkedIn industry IDs (deprecated — use /signals/industries)","description":"Find the LinkedIn industry ID for an industry name, so you can filter\ncompany search by industry instead of guessing numeric codes.\n\n`GET /api/v1/enrichment/company-search` takes `industryId`, but the IDs are not\nguessable and appear nowhere in a company payload. This endpoint is the lookup:\nsearch by name, take the `id`, pass it to company-search.\n\n**Cost:** Free. No credits, no rate concerns — it is a static list.\n\n**Call it with no parameters to get the complete taxonomy** (all 434 industries,\n~90 KB). That is the intended way to build an integration: pull the vocabulary\nonce, store it, map your own categories onto the IDs. There is no pagination and\nno default page size to trip over.\n\n**Input:**\n- `search` *(optional)* — an industry or sector name, e.g. `\"software\"`, `\"banking\"`,\n  `\"Manufacturing\"`. Case-insensitive. Matching also covers the hierarchy path, so a\n  sector name returns every industry beneath it.\n- `limit` *(optional)* — cap the number of entries returned. Omit it and you get\n  them all.\n\n**Output** — `data` contains:\n- `elements` — array, best match first (exact name, then prefix, then substring).\n  Each has `id` (string — pass this as `industryId`), `name`, and `path`\n  (full hierarchy, parents first).\n- `count` — how many entries are in `elements`.\n- `total` — how many matched in total. It equals `count` unless you passed\n  `limit`, so `total > count` is the only signal that you truncated the list.\n\n**Example:** `?search=software` returns `id: \"4\"` for `Software Development`; then\n`GET /api/v1/enrichment/company-search?industryId=4&keywords=crm` returns only\nsoftware-development companies. Pass several IDs comma-separated to widen the search.","operationId":"enrichment_linkedin_industries_api_v1_enrichment_linkedin_industries_get","deprecated":true,"security":[{"BearerAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Industry or sector name to look up, e.g. \"software\", \"banking\". Omit it to return the complete taxonomy.","title":"Search"},"description":"Industry or sector name to look up, e.g. \"software\", \"banking\". Omit it to return the complete taxonomy."},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"description":"Optional cap on how many entries come back. Omit it to get them all.","title":"Limit"},"description":"Optional cap on how many entries come back. Omit it to get them all."}],"responses":{"200":{"description":"Matching industries.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"elements":{"anyOf":[{"items":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"LinkedIn industry ID — pass as a `industryId` value on company-search"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Industry name, e.g. \"Software Development\""},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"Full position in the taxonomy, parents first, e.g. \"Technology, Information and Media > Technology, Information and Internet > Software Development\". A path with no `>` is one of the 20 top-level sectors."}},"additionalProperties":true,"type":"object","title":"_IndustryElement"},"type":"array"},{"type":"null"}],"title":"Elements","description":"Matching industries, best match first"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count","description":"How many entries are in `elements`"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"How many industries matched in total. Equal to `count` unless you passed `limit`, so `total > count` is the only way to know you truncated the list."}},"additionalProperties":true,"type":"object","title":"_IndustriesData"},{"type":"null"}],"description":"Industry lookup payload"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"LinkedinIndustriesResponse","description":"Typed response for the industry lookup endpoint."},"example":{"data":{"elements":[{"id":"4","name":"Software Development","path":"Technology, Information and Media > Technology, Information and Internet > Software Development"},{"id":"3102","name":"IT System Custom Software Development","path":"Professional Services > IT Services and IT Consulting > IT System Custom Software Development"}],"count":434,"total":434},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"search","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/people-search":{"post":{"tags":["Enrichment"],"summary":"Search for people","description":"Find LinkedIn profiles at target companies with specific job titles or seniority levels—each result includes an AI-verified qualification verdict showing whether the profile actually matches your criteria.\n\n**Input:** filter criteria—`companies` (names, LinkedIn URLs, or IDs), `jobTitles`, `excludeJobTitles`, `locations`, `geoIds`, `seniorityLevels`, `companySize`, `industryId` (LinkedIn industry IDs, resolve via `/enrichment/linkedin-industries`), `companyHeadquarterLocations` (where the company is headquartered, as opposed to `locations` which is where the person is), plus `excludeIndustryId` and `excludeCompanyHeadquarterLocations`; `page` for pagination (1-100, up to 25 results per page). Optional: `webhookUrl` and `deliveryMode` for async delivery, `qualifiedOnly` to exclude disqualified matches, `metadata` to correlate responses.\n\n**Output:** (sync: 200 OK, or async: 202 Accepted → webhook POST) Array of up to 25 LinkedIn profiles per page with `linkedinUrl`, `firstName`, `lastName`, `location`, `openProfile`, `premium`, and `currentPositions` (company name, title, LinkedIn URL, start date). Each profile includes `qualificationStatus` (QUALIFIED or DISQUALIFIED) and `qualificationReason` explaining the verdict. Response includes pagination metadata (`count`, `page`, `totalPages`, `total`, `hasMore`) and `aiValidationStatus` (ok or unavailable—if unavailable, all results default to QUALIFIED so the response stays usable).","operationId":"enrichment_people_search_post_api_v1_enrichment_people_search_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"companies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Companies","description":"Company names, LinkedIn company URLs, or numeric LinkedIn company IDs. Mix freely in the same array. Max 50."},"jobTitles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Jobtitles","description":"Current job titles to include. Max 70."},"excludeJobTitles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Excludejobtitles","description":"Job titles to exclude. Max 70."},"locations":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Locations","description":"Location names (e.g. France, San Francisco). Each entry is one place: a qualified name such as \"Lyon, France\" is resolved as a whole, and a name that cannot be resolved returns 422 UNRESOLVED_LOCATION. For precise filtering, use geoIds instead."},"geoIds":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Geoids","description":"LinkedIn geo IDs for precise location filtering. Use /enrichment/linkedin-geo-id to resolve."},"seniorityLevels":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Senioritylevels","description":"Seniority levels: Entry, Strategic, Senior, VP, CXO, Director, Manager, Partner, Owner"},"companySize":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Companysize","description":"Company size: Self-employed, 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+"},"industryId":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Industryid","description":"LinkedIn industry IDs of the person's current company, e.g. `[\"4\", \"96\"]` (a single comma-separated entry like `[\"4,96\"]` also works). Resolve IDs by name with GET /api/v1/enrichment/linkedin-industries. Max 70."},"excludeIndustryId":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Excludeindustryid","description":"LinkedIn industry IDs to exclude. Same format as industryId. Max 70."},"companyHeadquarterLocations":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Companyheadquarterlocations","description":"Filter on where the person's current company is HEADQUARTERED (free-text location names, e.g. [\"France\"]). Distinct from locations/geoIds, which filter on where the person is. Max 70."},"excludeCompanyHeadquarterLocations":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Excludecompanyheadquarterlocations","description":"Company headquarter locations to exclude. Max 70."},"page":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Page","description":"Page number (1-100). Default: 1. Each page returns up to 25 results.","default":1},"qualifiedOnly":{"type":"boolean","title":"Qualifiedonly","description":"When true, only return profiles with qualificationStatus=QUALIFIED. Disqualified results are dropped from the response (count and results shrink accordingly). Default false: return everything with the verdict flag set so the caller can decide.","default":false},"metadata":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Metadata","description":"Arbitrary pass-through array. Whatever you put here is echoed back verbatim and is NEVER used to filter the search. It is returned in the `metadata` field of the response (synchronous calls) and in every webhook payload (async calls — batch, each `per_result` POST, and failure callbacks alike). Use it to correlate responses with your own records: row IDs, campaign tags, source URLs, etc. Items may be strings or objects. Max 50 items, 10 KB serialized."},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Optional. When supplied, the endpoint switches to async mode: it returns 202 Accepted immediately with a `requestId`, runs the search in the background, and POSTs the full response body to this URL once. Use when your client has a tight HTTP timeout (some serverless platforms, n8n defaults, etc.). When omitted, the endpoint stays synchronous and returns results in the same HTTP response."},"deliveryMode":{"type":"string","title":"Deliverymode","description":"Webhook delivery shape. Ignored when `webhookUrl` is omitted. `batch` (default) POSTs one payload containing every result. `per_result` POSTs one payload per result, each carrying `index` / `total` so the receiver can reassemble. Failed jobs always deliver one error payload regardless of mode; empty result sets emit no per-result POSTs (poll the GET endpoint to confirm completion).","default":"batch"}},"additionalProperties":true,"type":"object","title":"PeopleSearchRequest","description":"JSON body for POST /api/v1/enrichment/people-search.","example":{"companies":["Lemlist","https://www.linkedin.com/company/google/","1441"],"companyHeadquarterLocations":["France"],"companySize":["51-200","201-500"],"deliveryMode":"batch","excludeJobTitles":["intern","assistant"],"geoIds":["105015875"],"industryId":["4"],"jobTitles":["VP of Sales","Head of Marketing"],"locations":["France","Belgium"],"metadata":[{"campaign":"q3-france-founders","rowId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"page":1,"qualifiedOnly":false,"seniorityLevels":["VP","Director"],"webhookUrl":"https://your-server.com/webhooks/people-search"}}}},"required":true},"responses":{"200":{"description":"Synchronous result (no `webhookUrl` in the body).","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"results":{"anyOf":[{"items":{"properties":{"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl","description":"Profile URL"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname","description":"First name"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname","description":"Last name"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location string"},"openProfile":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Openprofile","description":"True if the profile is an Open Profile (messageable without connection)"},"premium":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Premium","description":"True if the member has a premium account"},"currentPositions":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname","description":"Company name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Job title at the company"},"companyLinkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylinkedinurl","description":"Company LinkedIn page URL"},"startedOnYear":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Startedonyear","description":"Year the person started this position"},"startedOnMonth":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Startedonmonth","description":"Month (1-12) the person started this position"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchPosition"},"type":"array"},{"type":"null"}],"title":"Currentpositions","description":"Current positions held by the person"},"qualificationStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Qualificationstatus","description":"AI qualification verdict, one of: QUALIFIED, DISQUALIFIED"},"qualificationReason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Qualificationreason","description":"Human-readable explanation for the qualification verdict"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchResult"},"type":"array"},{"type":"null"}],"title":"Results","description":"Matching profiles (up to 25 per page)"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count","description":"Number of results on this page"},"page":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page","description":"Current page number (1-based)"},"totalPages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalpages","description":"Total number of pages available"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Total number of matching profiles"},"hasMore":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasmore","description":"True if more pages are available"},"aiValidationStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aivalidationstatus","description":"AI qualification pass status, one of: ok (normal), unavailable (AI call failed; every result is defaulted to QUALIFIED)"},"metadata":{"anyOf":[{"items":{"properties":{"rowId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rowid","description":"Caller-supplied row identifier echoed back for this request"},"campaign":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign","description":"Caller-supplied campaign identifier echoed back for this request"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchMetadata"},"type":"array"},{"type":"null"}],"title":"Metadata","description":"Caller-supplied metadata echoed back for this request"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchData"},{"type":"null"}],"description":"People search payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"PeopleSearchResponse","description":"Typed response for /enrichment/people-search."},"example":{"data":{"results":[{"linkedinUrl":"https://www.linkedin.com/in/jane-doe-vp-sales/","firstName":"Jane","lastName":"Doe","location":"Paris, Île-de-France, France","openProfile":false,"premium":true,"currentPositions":[{"companyName":"Lemlist","title":"VP of Sales","companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","startedOnYear":2024,"startedOnMonth":3}],"qualificationStatus":"QUALIFIED","qualificationReason":"title 'VP of Sales' matches jobTitles"},{"linkedinUrl":"https://www.linkedin.com/in/john-smith-marketing/","firstName":"John","lastName":"Smith","location":"Brussels, Belgium","openProfile":true,"premium":false,"currentPositions":[{"companyName":"Lemlist","title":"Marketing Director","companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","startedOnYear":2023,"startedOnMonth":9}],"qualificationStatus":"DISQUALIFIED","qualificationReason":"title 'Marketing Director' not in jobTitles (VP of Sales, Head of Marketing)"}],"count":2,"page":1,"totalPages":4,"total":87,"hasMore":true,"aiValidationStatus":"ok","metadata":[{"rowId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","campaign":"q3-france-founders"}]},"requestId":"1f3c2a7e-9b5d-4d2a-8f4b-9a0e7c1d3b22"}}}},"202":{"description":"Accepted for async processing — `webhookUrl` was provided.","content":{"application/json":{"schema":{"properties":{"requestId":{"type":"string","title":"Requestid"},"status":{"type":"string","title":"Status","description":"One of: pending, completed, failed"}},"type":"object","required":["requestId","status"],"title":"PeopleSearchAsyncAccepted","description":"Response when ``webhookUrl`` is supplied — the search runs async."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"body","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/enrichment/people-search/{request_id}":{"get":{"tags":["Enrichment"],"summary":"Poll an async people-search request","description":"Check the status and retrieve results of an async people-search request—use when your webhook receiver was temporarily unavailable or you prefer polling over webhooks.\n\n**Input:** `requestId` (the ID from your initial async POST response).\n\n**Output:** job status (pending/completed/failed); when complete, search results in your configured format (batch: full page of results; per-result: page metadata only, with individual results already streamed to your webhook one-by-one); `webhookDeliveredCount` and `webhookFailedCount` show successful and failed webhook POSTs so you can detect partial failures and decide whether to refetch.","operationId":"enrichment_people_search_get_job_api_v1_enrichment_people_search__request_id__get","security":[{"BearerAuth":[]}],"parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"responses":{"200":{"description":"Job state. Inspect `status` to know whether to consume `result` (completed) or `error` (failed) or wait (pending).","content":{"application/json":{"schema":{"properties":{"requestId":{"type":"string","title":"Requestid","examples":["1f3c2a7e-9b5d-4d2a-8f4b-9a0e7c1d3b22"]},"status":{"type":"string","title":"Status","description":"One of: pending, completed, failed","examples":["completed"]},"result":{"anyOf":[{"properties":{"results":{"anyOf":[{"items":{"properties":{"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl","description":"Profile URL"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname","description":"First name"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname","description":"Last name"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Location string"},"openProfile":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Openprofile","description":"True if the profile is an Open Profile (messageable without connection)"},"premium":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Premium","description":"True if the member has a premium account"},"currentPositions":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname","description":"Company name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Job title at the company"},"companyLinkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylinkedinurl","description":"Company LinkedIn page URL"},"startedOnYear":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Startedonyear","description":"Year the person started this position"},"startedOnMonth":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Startedonmonth","description":"Month (1-12) the person started this position"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchPosition"},"type":"array"},{"type":"null"}],"title":"Currentpositions","description":"Current positions held by the person"},"qualificationStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Qualificationstatus","description":"AI qualification verdict, one of: QUALIFIED, DISQUALIFIED"},"qualificationReason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Qualificationreason","description":"Human-readable explanation for the qualification verdict"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchResult"},"type":"array"},{"type":"null"}],"title":"Results","description":"Matching profiles (up to 25 per page)"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count","description":"Number of results on this page"},"page":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page","description":"Current page number (1-based)"},"totalPages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalpages","description":"Total number of pages available"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"Total number of matching profiles"},"hasMore":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasmore","description":"True if more pages are available"},"aiValidationStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aivalidationstatus","description":"AI qualification pass status, one of: ok (normal), unavailable (AI call failed; every result is defaulted to QUALIFIED)"},"metadata":{"anyOf":[{"items":{"properties":{"rowId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rowid","description":"Caller-supplied row identifier echoed back for this request"},"campaign":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaign","description":"Caller-supplied campaign identifier echoed back for this request"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchMetadata"},"type":"array"},{"type":"null"}],"title":"Metadata","description":"Caller-supplied metadata echoed back for this request"}},"additionalProperties":true,"type":"object","title":"_PeopleSearchData"},{"type":"null"}],"description":"Full search response body when status=completed — the same shape the synchronous POST returns, so one generated type serves both. `null` while status=pending or status=failed. For `per_result` jobs this carries the first page's metadata (totalPages, aiValidationStatus, etc.) but an empty `results` array — the actual rows were streamed to your webhook one by one."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Set only when status=failed. Short, human-readable reason the lookup could not complete.","examples":[null]},"webhookDeliveredCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Webhookdeliveredcount","description":"Number of webhook POSTs that landed (2xx response). For `batch` jobs this is 0 or 1; for `per_result` jobs it counts successful per-item deliveries. `null` when no webhook was configured.","examples":[25]},"webhookFailedCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Webhookfailedcount","description":"Number of webhook POSTs that errored (non-2xx, timeout, or connection refused). Use to detect partial delivery and decide whether to refetch via this GET endpoint. `null` when no webhook was configured.","examples":[0]}},"type":"object","required":["requestId","status"],"title":"PeopleSearchJobResponse","description":"Async job state — returned by GET /enrichment/people-search/{requestId}.","example":{"requestId":"1f3c2a7e-9b5d-4d2a-8f4b-9a0e7c1d3b22","result":{"aiValidationStatus":"ok","count":2,"hasMore":true,"metadata":[{"campaign":"q3-france-founders","rowId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}],"page":1,"results":[{"currentPositions":[{"companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","companyName":"Lemlist","startedOnMonth":3,"startedOnYear":2024,"title":"VP of Sales"}],"firstName":"Jane","lastName":"Doe","linkedinUrl":"https://www.linkedin.com/in/jane-doe-vp-sales/","location":"Paris, Île-de-France, France","openProfile":false,"premium":true,"qualificationReason":"title 'VP of Sales' matches jobTitles","qualificationStatus":"QUALIFIED"},{"currentPositions":[{"companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","companyName":"Lemlist","startedOnMonth":9,"startedOnYear":2023,"title":"Marketing Director"}],"firstName":"John","lastName":"Smith","linkedinUrl":"https://www.linkedin.com/in/john-smith-marketing/","location":"Brussels, Belgium","openProfile":true,"premium":false,"qualificationReason":"title 'Marketing Director' not in jobTitles (VP of Sales, Head of Marketing)","qualificationStatus":"DISQUALIFIED"}],"total":87,"totalPages":4},"status":"completed","webhookDeliveredCount":25,"webhookFailedCount":0}},"examples":{"completed_batch":{"summary":"batch job — full page in `result`, one webhook POST delivered","value":{"requestId":"1f3c2a7e-9b5d-4d2a-8f4b-9a0e7c1d3b22","status":"completed","result":{"results":[{"linkedinUrl":"https://www.linkedin.com/in/jane-doe-vp-sales/","firstName":"Jane","lastName":"Doe","location":"Paris, Île-de-France, France","openProfile":false,"premium":true,"currentPositions":[{"companyName":"Lemlist","title":"VP of Sales","companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","startedOnYear":2024,"startedOnMonth":3}],"qualificationStatus":"QUALIFIED","qualificationReason":"title 'VP of Sales' matches jobTitles"},{"linkedinUrl":"https://www.linkedin.com/in/john-smith-marketing/","firstName":"John","lastName":"Smith","location":"Brussels, Belgium","openProfile":true,"premium":false,"currentPositions":[{"companyName":"Lemlist","title":"Marketing Director","companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","startedOnYear":2023,"startedOnMonth":9}],"qualificationStatus":"DISQUALIFIED","qualificationReason":"title 'Marketing Director' not in jobTitles (VP of Sales, Head of Marketing)"}],"count":2,"page":1,"totalPages":4,"total":87,"hasMore":true,"aiValidationStatus":"ok","metadata":[{"rowId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","campaign":"q3-france-founders"}]},"webhookDeliveredCount":1,"webhookFailedCount":0}},"completed_per_result":{"summary":"per_result job — rows for this page were streamed one webhook POST each; counts show how many landed","value":{"requestId":"1f3c2a7e-9b5d-4d2a-8f4b-9a0e7c1d3b22","status":"completed","result":{"results":[{"linkedinUrl":"https://www.linkedin.com/in/jane-doe-vp-sales/","firstName":"Jane","lastName":"Doe","location":"Paris, Île-de-France, France","openProfile":false,"premium":true,"currentPositions":[{"companyName":"Lemlist","title":"VP of Sales","companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","startedOnYear":2024,"startedOnMonth":3}],"qualificationStatus":"QUALIFIED","qualificationReason":"title 'VP of Sales' matches jobTitles"},{"linkedinUrl":"https://www.linkedin.com/in/john-smith-marketing/","firstName":"John","lastName":"Smith","location":"Brussels, Belgium","openProfile":true,"premium":false,"currentPositions":[{"companyName":"Lemlist","title":"Marketing Director","companyLinkedinUrl":"https://www.linkedin.com/company/lemlist/","startedOnYear":2023,"startedOnMonth":9}],"qualificationStatus":"DISQUALIFIED","qualificationReason":"title 'Marketing Director' not in jobTitles (VP of Sales, Head of Marketing)"}],"count":2,"page":1,"totalPages":4,"total":87,"hasMore":true,"aiValidationStatus":"ok","metadata":[{"rowId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","campaign":"q3-france-founders"}]},"webhookDeliveredCount":23,"webhookFailedCount":2}},"pending":{"summary":"Still running — poll again in a few seconds","value":{"requestId":"1f3c2a7e-9b5d-4d2a-8f4b-9a0e7c1d3b22","status":"pending","webhookDeliveredCount":0,"webhookFailedCount":0}},"failed":{"summary":"Search failed — read `error` and decide whether to retry","value":{"requestId":"1f3c2a7e-9b5d-4d2a-8f4b-9a0e7c1d3b22","status":"failed","error":"People search failed unexpectedly. Please retry.","webhookDeliveredCount":0,"webhookFailedCount":1}}}}}},"404":{"description":"No request found for this ID under your account. Either the request ID is wrong, results have aged out (1 h TTL), or the ID belongs to a different account.","content":{"application/json":{"example":{"detail":"Not found."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"request_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/phone":{"post":{"tags":["Enrichment"],"summary":"Submit a phone enrichment request","description":"Look up a prospect's direct business phone number using their name, company, and optionally their LinkedIn profile — enabling warm outreach and contact validation for B2B sales and recruiting.\n\n**Input:** `firstName`, `lastName`, `company` (required); `linkedinUrl`, `email` (optional — significantly improve hit rate when provided); `webhookUrl` (optional — for async delivery).\n\n**Output:** An E.164-formatted phone number (if found) returned via polling `GET /api/v1/enrichment/phone/{enrichmentId}` or POSTed to your `webhookUrl` once lookup completes (typically 30s–5min). Response includes `status` (`pending`, `completed`, or `failed`), `phone` (null if not found), and `creditsCharged` (5 on success, 0 otherwise). Job state retained for 1 hour after submission.","operationId":"submit_phone_enrichment_api_v1_enrichment_phone_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"firstName":{"type":"string","maxLength":100,"minLength":1,"title":"Firstname"},"lastName":{"type":"string","maxLength":100,"minLength":1,"title":"Lastname"},"company":{"type":"string","maxLength":255,"minLength":1,"title":"Company","description":"Company name or domain"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl","description":"LinkedIn profile URL — significantly improves accuracy when provided"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email","description":"Known email address — improves matching"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Optional webhook to receive the result. POSTed once when the job completes (success OR failure). Customers can also poll the GET endpoint instead."}},"type":"object","required":["firstName","lastName","company"],"title":"PhoneEnrichmentCreate","description":"Submit a phone enrichment request.\n\nPhone lookup typically takes 30s-5min, which is too long for a sync HTTP\ncall. Submit returns a job ID immediately; poll the GET endpoint or set\n``webhookUrl`` to receive the result via webhook.","examples":[{"company":"Acme Corp","email":"marie.dupont@acme.com","firstName":"Marie","lastName":"Dupont","linkedinUrl":"https://linkedin.com/in/marie-dupont","webhookUrl":"https://your-server.com/webhooks/phone"}]}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"enrichmentId":{"type":"string","title":"Enrichmentid"},"status":{"type":"string","title":"Status","description":"One of: pending, completed, failed"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone","description":"E.164 phone number; null if not found"},"creditsCharged":{"type":"integer","title":"Creditscharged","description":"Credits deducted (5 on success, 0 otherwise)","default":0},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["enrichmentId","status"],"title":"PhoneEnrichmentJobResponse","description":"Phone enrichment job state."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"firstName","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/enrichment/phone/{enrichment_id}":{"get":{"tags":["Enrichment"],"summary":"Poll a phone enrichment result","description":"Check the status and result of a phone enrichment lookup you submitted — poll this endpoint until the job completes and receive the contact's phone number if Rodz found a match.\n\n**Input:** enrichmentId (the job ID returned from your POST submission)\n\n**Output:** Current status (pending while running, completed when done, or failed if the lookup errored), the E.164 phone number if found (or null if no match), credits charged (5 if successful, 0 otherwise), and error details if applicable. Job records are kept for 1 hour after submission.","operationId":"get_phone_enrichment_api_v1_enrichment_phone__enrichment_id__get","security":[{"BearerAuth":[]}],"parameters":[{"name":"enrichment_id","in":"path","required":true,"schema":{"type":"string","title":"Enrichment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"enrichmentId":{"type":"string","title":"Enrichmentid"},"status":{"type":"string","title":"Status","description":"One of: pending, completed, failed"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone","description":"E.164 phone number; null if not found"},"creditsCharged":{"type":"integer","title":"Creditscharged","description":"Credits deducted (5 on success, 0 otherwise)","default":0},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["enrichmentId","status"],"title":"PhoneEnrichmentJobResponse","description":"Phone enrichment job state."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"enrichment_id","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/post-comments":{"get":{"tags":["Enrichment"],"summary":"Get post comments","description":"Discover who is actively engaging with a LinkedIn post — surface prospects already commenting on content relevant to your market, with the exact words they used.\n\n**Input:** the LinkedIn post URL or activity ID (`post`, required). Optionally sort with `sortBy` (`relevance`, the default, or `date`), and page through results with `page` (1-based) or the `paginationToken` returned by a previous call.\n\n**Output:** a page of commenters, each with their profile data (name, headline, LinkedIn URL, profile picture) and their comment (`commentText`, `createdAt`), plus a per-comment id/permalink. When more results exist, a `paginationToken` is returned under `pagination` — pass it back to fetch the next page. Costs 0.5 credits per page that returns commenters; empty pages are free.","operationId":"enrichment_post_comments_api_v1_enrichment_post_comments_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"post","in":"query","required":true,"schema":{"type":"string","description":"LinkedIn post URL or activity ID","title":"Post"},"description":"LinkedIn post URL or activity ID"},{"name":"sortBy","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sort order: 'relevance' (default) or 'date'","title":"Sortby"},"description":"Sort order: 'relevance' (default) or 'date'"},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Page number (1-based)","title":"Page"},"description":"Page number (1-based)"},{"name":"paginationToken","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Token from a previous page's response","title":"Paginationtoken"},"description":"Token from a previous page's response"}],"responses":{"200":{"description":"One page of people who commented on the post.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"elements":{"anyOf":[{"items":{"properties":{"commentId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commentid","description":"The comment's own stable ID — use as the de-duplication key"},"commentUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commenturl","description":"Permalink to the comment (also unique per comment)"},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"LinkedIn member ID of the commenter (not the comment ID)"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Commenter full name"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl","description":"Commenter profile URL"},"position":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Position","description":"Headline / current position (may be null)"},"pictureUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pictureurl","description":"Profile picture URL (may be null)"},"commentText":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commenttext","description":"The comment body"},"createdAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdat","description":"ISO-8601 timestamp of the comment (may be null)"},"isAuthor":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isauthor","description":"True when the commenter is the post's author replying"}},"additionalProperties":true,"type":"object","title":"_PostCommentsElement"},"type":"array"},{"type":"null"}],"title":"Elements","description":"Comments on the post"},"pagination":{"anyOf":[{"properties":{"paginationToken":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paginationtoken","description":"Token to pass to fetch the next page (absent on the last page)"}},"additionalProperties":true,"type":"object","title":"_PostCommentsPagination"},{"type":"null"}],"description":"Pagination cursor"}},"additionalProperties":true,"type":"object","title":"_PostCommentsData"},{"type":"null"}],"description":"One page of comments, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"PostCommentsResponse","description":"Typed response for /enrichment/post-comments."},"example":{"data":{"elements":[{"commentId":"7469631311012577280","commentUrl":"https://www.linkedin.com/feed/update/urn:li:ugcPost:7469496436737495042?commentUrn=urn%3Ali%3Acomment%3A%28ugcPost%3A7469496436737495042%2C7469631311012577280%29","id":"ACoAAB1exampleProfileUrnZ","name":"Marie Dupont","linkedinUrl":"https://www.linkedin.com/in/marie-dupont","position":"VP Engineering at Lemlist","pictureUrl":"https://media.licdn.com/dms/image/v2/example/profile-displayphoto-shrink_400_400/0/1736826818808","commentText":"Congrats on the launch — this is exactly what our team needed!","createdAt":"2026-05-31T15:02:00.000Z","isAuthor":false}],"pagination":{"paginationToken":"dXJuOmxpOmFjdGl2aXR5Ojc0NDU5Mzc2MjI3MTMyMjExMjA="}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"post","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/post-reactions":{"get":{"tags":["Enrichment"],"summary":"Get post reactions","description":"Discover who reacted to a LinkedIn post — find engaged prospects and build targeted outreach lists from people who showed interest in specific content.\n\n**Input:** LinkedIn post URL or activity ID (`post`), with optional pagination control via page number (`page`) or cursor token (`paginationToken`).\n\n**Output:** One page of people who reacted, each with LinkedIn member ID, name, headline/position, LinkedIn profile URL, profile picture URL, and reaction type (LIKE, PRAISE, EMPATHY, APPRECIATION, INTEREST, or ENTERTAINMENT). Includes a pagination token to fetch the next page (omitted on the last page). Cost: 0.5 credits per page (billed only if the page contains people; empty pages are free).","operationId":"enrichment_post_reactions_api_v1_enrichment_post_reactions_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"post","in":"query","required":true,"schema":{"type":"string","description":"LinkedIn post URL or activity ID","title":"Post"},"description":"LinkedIn post URL or activity ID"},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Page number (1-based)","title":"Page"},"description":"Page number (1-based)"},{"name":"paginationToken","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Token from a previous page's response","title":"Paginationtoken"},"description":"Token from a previous page's response"}],"responses":{"200":{"description":"One page of people who reacted to the post.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"elements":{"anyOf":[{"items":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"LinkedIn member ID of the person who reacted"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Full name"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl","description":"Profile URL"},"position":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Position","description":"Headline / current position (may be null)"},"pictureUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pictureurl","description":"Profile picture URL (may be null)"},"reactionType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reactiontype","description":"Reaction the person left, one of: LIKE, PRAISE, EMPATHY, APPRECIATION, INTEREST, ENTERTAINMENT"}},"additionalProperties":true,"type":"object","title":"_PostReactionsElement"},"type":"array"},{"type":"null"}],"title":"Elements","description":"People who reacted to the post"},"pagination":{"anyOf":[{"properties":{"paginationToken":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paginationtoken","description":"Token to pass to fetch the next page (absent on the last page)"}},"additionalProperties":true,"type":"object","title":"_PostReactionsPagination"},{"type":"null"}],"description":"Pagination cursor"}},"additionalProperties":true,"type":"object","title":"_PostReactionsData"},{"type":"null"}],"description":"One page of reactions, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"PostReactionsResponse","description":"Typed response for /enrichment/post-reactions."},"example":{"data":{"elements":[{"id":"ACoAAB1exampleProfileUrnZ","name":"Marie Dupont","linkedinUrl":"https://www.linkedin.com/in/marie-dupont","position":"VP Engineering at Lemlist","pictureUrl":"https://media.licdn.com/dms/image/v2/example/profile-displayphoto-shrink_400_400/0/1736826818808","reactionType":"PRAISE"}],"pagination":{"paginationToken":"dXJuOmxpOmFjdGl2aXR5Ojc0NDU5Mzc2MjI3MTMyMjExMjA="}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"post","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/profile-posts":{"get":{"tags":["Enrichment"],"summary":"Get profile posts","description":"Retrieve any LinkedIn profile's recent posts — their activity, content, images, and audience engagement (likes, comments, shares, and reaction-type breakdowns). Monitor prospect movements and announcements, track competitor activity, or research industry leaders and their signals.\n\n**Input:** LinkedIn profile identifier (`profile` URL, `profileId`, or `profilePublicIdentifier` — the last URL segment is fastest); optionally filter posts by age using `scrapePostedLimit` (`1h`, `24h`, `week`, `month`, `3months`, `6months`, `year`).\n\n**Output:** Array of posts (newest first) with content text, author metadata (name, headline, profile link), images, posting timestamps, and engagement counts (likes, comments, shares, plus a per-reaction-type breakdown); paginate by passing `paginationToken` back on the next request.","operationId":"enrichment_profile_posts_api_v1_enrichment_profile_posts_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"LinkedIn profile URL","title":"Profile"},"description":"LinkedIn profile URL"},{"name":"profileId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"LinkedIn profile ID (faster)","title":"Profileid"},"description":"LinkedIn profile ID (faster)"},{"name":"profilePublicIdentifier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Profile public identifier (last part of URL)","title":"Profilepublicidentifier"},"description":"Profile public identifier (last part of URL)"},{"name":"scrapePostedLimit","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Time filter: 1h, 24h, week, month, 3months, 6months, year","title":"Scrapepostedlimit"},"description":"Time filter: 1h, 24h, week, month, 3months, 6months, year"},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Page number","title":"Page"},"description":"Page number"},{"name":"paginationToken","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pagination token from previous page","title":"Paginationtoken"},"description":"Pagination token from previous page"}],"responses":{"200":{"description":"Recent posts for the profile.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"elements":{"anyOf":[{"items":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"author":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"universalName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universalname"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"\"profile\" or \"company\""},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"info":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Info"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"websiteLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Websitelabel"},"avatar":{"anyOf":[{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_PostImage"},{"type":"null"}]},"urn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Urn"}},"additionalProperties":true,"type":"object","title":"_PostAuthor"},{"type":"null"}]},"postedAt":{"anyOf":[{"properties":{"timestamp":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timestamp"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"postedAgoShort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagoshort"},"postedAgoText":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagotext"}},"additionalProperties":true,"type":"object","title":"_PostedAt"},{"type":"null"}]},"postImages":{"anyOf":[{"items":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_PostImage"},"type":"array"},{"type":"null"}],"title":"Postimages"},"shareUrn":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shareurn"},"shareLinkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sharelinkedinurl"},"entityId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entityid"},"engagement":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"likes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Likes"},"comments":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Comments"},"shares":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Shares"},"reactions":{"anyOf":[{"items":{"properties":{"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count"}},"additionalProperties":true,"type":"object","title":"_PostReactionCount"},"type":"array"},{"type":"null"}],"title":"Reactions"}},"additionalProperties":true,"type":"object","title":"_PostEngagement"},{"type":"null"}]},"contentAttributes":{"anyOf":[{"items":{"properties":{"start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start"},"length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Length"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type","description":"Entity kind, e.g. \"COMPANY_NAME\" or \"PROFILE_MENTION\""},"hyperlink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hyperlink"},"textLink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Textlink"},"company":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"},"universalName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universalname"}},"additionalProperties":true,"type":"object","title":"_PostContentEntityCompany","description":"Company referenced by a COMPANY_NAME entity in ``contentAttributes``."},{"type":"null"}]},"profile":{"anyOf":[{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"}},"additionalProperties":true,"type":"object","title":"_PostContentEntityProfile","description":"Person referenced by a PROFILE_MENTION entity in ``contentAttributes``."},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_PostContentAttribute","description":"One span of rich text inside ``content``.\n\n``start``/``length`` index into ``content``. Which nested object is present\nfollows ``type``: ``COMPANY_NAME`` carries ``company``, ``PROFILE_MENTION``\ncarries ``profile``. Both are optional because a hyperlink entity carries\nneither."},"type":"array"},{"type":"null"}],"title":"Contentattributes","description":"Rich-text spans inside `content` (mentions, links)"},"article":{"anyOf":[{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link"},"linkLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linklabel"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"image":{"anyOf":[{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_PostArticleImage"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_PostArticle","description":"Link preview when the post shares an external article."},{"type":"null"}],"description":"Link preview, when the post shares one"},"socialContent":{"anyOf":[{"properties":{"hideCommentsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidecommentscount"},"hideReactionsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidereactionscount"},"hideSocialActivityCounts":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidesocialactivitycounts"},"hideShareAction":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hideshareaction"},"hideSendAction":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hidesendaction"},"hideRepostsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hiderepostscount"},"hideViewsCount":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hideviewscount"},"showContributionExperience":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Showcontributionexperience"},"showSocialDetail":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Showsocialdetail"},"shareUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shareurl"},"trustInterventionBanner":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trustinterventionbanner"}},"additionalProperties":true,"type":"object","title":"_PostSocialContent","description":"Display flags LinkedIn attaches to the post."},{"type":"null"}]},"header":{"anyOf":[{"properties":{"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"}},"additionalProperties":true,"type":"object","title":"_PostHeader"},{"type":"null"}]},"postVideo":{"anyOf":[{"properties":{"thumbnailUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnailurl"},"videoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Videourl"}},"additionalProperties":true,"type":"object","title":"_PostVideo","description":"Present when the post carries a native video."},{"type":"null"}],"description":"Native video attached to the post"},"document":{"anyOf":[{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"transcribedDocumentUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transcribeddocumenturl"},"coverPages":{"anyOf":[{"items":{"properties":{"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"imageUrls":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Imageurls"}},"additionalProperties":true,"type":"object","title":"_PostDocumentCoverPage"},"type":"array"},{"type":"null"}],"title":"Coverpages"}},"additionalProperties":true,"type":"object","title":"_PostDocument","description":"Present when the post carries a document/carousel. Profile posts only."},{"type":"null"}],"description":"Attached document/carousel. Profile posts only."},"repostedBy":{"anyOf":[{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"publicIdentifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publicidentifier"},"universalName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universalname"},"linkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"}},"additionalProperties":true,"type":"object","title":"_PostRepostedBy","description":"Original author when this element is a repost. Profile posts only."},{"type":"null"}],"description":"Original author when this element is a repost. Profile posts only."},"repostedAt":{"anyOf":[{"properties":{"timestamp":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Timestamp"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"postedAgoShort":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagoshort"},"postedAgoText":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postedagotext"}},"additionalProperties":true,"type":"object","title":"_PostedAt"},{"type":"null"}],"description":"When the repost happened. Profile posts only."},"comments":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Comments","description":"Always an empty array on the post-list endpoints — a post list does not expand comments, regardless of `engagement.comments`. Use GET /enrichment/post-comments to fetch them."}},"additionalProperties":true,"type":"object","title":"_PostElement"},"type":"array"},{"type":"null"}],"title":"Elements"},"pagination":{"anyOf":[{"properties":{"totalElements":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalelements"},"totalPages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Totalpages"},"pageNumber":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pagenumber"},"previousElements":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Previouselements"},"pageSize":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pagesize"},"paginationToken":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paginationtoken"}},"additionalProperties":true,"type":"object","title":"_PostsPagination"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_PostsData"},{"type":"null"}],"description":"Posts payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Why no posts were returned, when `data` is null. Otherwise null."}},"additionalProperties":true,"type":"object","title":"PostsResponse","description":"Typed response for the posts endpoints (profile & company)."},"example":{"data":{"elements":[{"id":"7469496437156925441","linkedinUrl":"https://www.linkedin.com/posts/marie-dupont_hiring-activity-7469496437156925441-88oN","content":"We just shipped our new analytics dashboard 🎉 — and we're hiring two senior engineers to take it further. DM me if you're interested.","contentAttributes":[{"start":0,"length":7,"type":"COMPANY_NAME","company":{"id":"5366","name":"Lemlist","linkedinUrl":"https://www.linkedin.com/company/lemlist/"}}],"author":{"id":"ACoAAB1exampleProfileUrnZ","publicIdentifier":"marie-dupont","type":"profile","name":"Marie Dupont","linkedinUrl":"https://www.linkedin.com/in/marie-dupont","info":"VP Engineering at Lemlist","website":"https://lemlist.com","websiteLabel":"Visit our site","avatar":{"url":"https://media.licdn.com/dms/image/v2/example/profile-displayphoto-shrink_800_800/0/1736826818808","width":800,"height":800},"urn":"251749025"},"postedAt":{"timestamp":1780866727151,"date":"2026-05-31T14:30:00.000Z","postedAgoShort":"1d","postedAgoText":"1 day ago • Visible to anyone on or off LinkedIn"},"postImages":[{"url":"https://media.licdn.com/dms/image/v2/example/feedshare-image-high-res/0/1780420456539","width":557,"height":896}],"article":{},"socialContent":{"hideCommentsCount":false,"hideReactionsCount":false,"hideSocialActivityCounts":false,"hideShareAction":false,"hideSendAction":false,"hideRepostsCount":false,"hideViewsCount":false,"hideReactAction":false,"hideCommentAction":false,"shareUrl":"https://www.linkedin.com/posts/marie-dupont_hiring-activity-7469496437156925441-88oN","showContributionExperience":false,"showSocialDetail":true},"comments":[],"header":{},"entityId":"7469496437156925441","shareUrn":"urn:li:ugcPost:7469496436737495040","shareLinkedinUrl":"https://www.linkedin.com/feed/update/urn:li:ugcPost:7469496436737495040","engagement":{"id":"7469496436737495042","likes":312,"comments":21,"shares":8,"reactions":[{"type":"LIKE","count":250},{"type":"PRAISE","count":40},{"type":"EMPATHY","count":22}]}}],"pagination":{"totalElements":0,"totalPages":0,"pageNumber":1,"previousElements":0,"pageSize":50,"paginationToken":"dXJuOmxpOmFjdGl2aXR5Ojc0NDU5Mzc2MjI3MTMyMjExMjA="}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Input should be a valid integer, unable to parse string as an integer","details":{"field":"page","message":"Input should be a valid integer, unable to parse string as an integer"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/reverse-email":{"get":{"tags":["Enrichment"],"summary":"Reverse lookup an email","description":"Identify who is behind an email address by retrieving their complete LinkedIn professional profile — useful for lead qualification, CRM enrichment, and sales intelligence.\n\n**Input:** `email` (the email address to look up), plus optional `firstName`, `lastName`, or `fullName` to improve matching accuracy.\n\n**Output:** The matched person's full LinkedIn profile data in `data.person` (including name, LinkedIn URL and ID, headline, current company, location, connections count, education, work history, skills, photo URL, and more), or null if no match is found. Successfully matched results are billed at 0.5 credits per call.","operationId":"enrichment_reverse_email_api_v1_enrichment_reverse_email_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","description":"Contact email address","title":"Email"},"description":"Contact email address"},{"name":"firstName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"First name","title":"Firstname"},"description":"First name"},{"name":"lastName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Last name","title":"Lastname"},"description":"Last name"},{"name":"fullName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full name","title":"Fullname"},"description":"Full name"}],"responses":{"200":{"description":"Matched person (`data.person`).","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"person":{"anyOf":[{"properties":{"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"middleName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Middlename"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"linkedInUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinurl"},"linkedInId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinid"},"linkedinSalesLink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinsaleslink","description":"Sales Navigator profile URN token (e.g. ACoAAB...)"},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline"},"activeCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Activecompany"},"numberOfCurrentCompanies":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Numberofcurrentcompanies"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Region"},"county":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"County"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"followers":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Followers","description":"Follower count as a string"},"followerCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Followercount"},"connectionsCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Connectionscount"},"isCreator":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Iscreator"},"isJobSeeker":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isjobseeker"},"isOpenLink":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isopenlink"},"isPremium":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ispremium"},"isVerified":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isverified"},"openProfileMessages":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Openprofilemessages"},"languages":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Languages","description":"Comma-separated language list"},"skillsList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skillslist","description":"Comma-separated skills"},"linkedinSummary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linkedinsummary"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"extractedGender":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extractedgender","description":"Inferred gender when available: one of \"male\", \"female\", or \"\" (unknown)"},"formerCompaniesList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Formercompanieslist","description":"Comma-separated former company names"},"education":{"anyOf":[{"properties":{"universitiesNamesList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universitiesnameslist"},"educationDetails":{"anyOf":[{"items":{"properties":{"startedOn":{"anyOf":[{"properties":{"year":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Year"}},"additionalProperties":true,"type":"object","title":"_PersonEducationYear"},{"type":"null"}],"description":"Start year. Education dates are year-granular; no month is available."},"endedOn":{"anyOf":[{"properties":{"year":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Year"}},"additionalProperties":true,"type":"object","title":"_PersonEducationYear"},{"type":"null"}],"description":"End year. Year-granular, like startedOn."},"universityName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Universityname"},"fieldsOfStudy":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Fieldsofstudy"},"socialUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Socialurl","description":"School LinkedIn URL, e.g. https://www.linkedin.com/company/15142508/"},"schoolId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schoolid","description":"LinkedIn school ID as a string, e.g. \"15142508\""},"schoolLogo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Schoollogo","description":"School logo image URL (empty when the school has none)"}},"additionalProperties":true,"type":"object","title":"_PersonEducationDetail"},"type":"array"},{"type":"null"}],"title":"Educationdetails"}},"additionalProperties":true,"type":"object","title":"_PersonEducation"},{"type":"null"}]},"certificationsList":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Certificationslist"},"certification":{"anyOf":[{"items":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Certification name, e.g. \"Machine Learning\""},"issuedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuedat","description":"Free text as displayed, e.g. \"Issued Jan 2017\" — not a date"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link","description":"URL of the certification itself"},"issuedBy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuedby","description":"Issuing organisation name"},"issuedByLink":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuedbylink","description":"LinkedIn URL of the issuing organisation"},"issuedByLogo":{"anyOf":[{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"sizes":{"anyOf":[{"items":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"}},"additionalProperties":true,"type":"object","title":"_ContactCertificationLogoSize"},"type":"array"},{"type":"null"}],"title":"Sizes"}},"additionalProperties":true,"type":"object","title":"_ContactCertificationLogo"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"_ContactCertification","description":"One certification on a person's profile.\n\nPreviously declared as a bare list (``items: {}``), so generated clients had\nto guess the field names — a customer reported silently producing all-null\nobjects for every certification (2026-08-05). Note ``issuedAt`` is free text\nas LinkedIn renders it (e.g. \"Issued Jan 2017\"), NOT a parseable date."},"type":"array"},{"type":"null"}],"title":"Certification","description":"Certification entries (empty when none)"},"currentCompanyDetail":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"jobTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitle"},"startTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"},"endTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime","description":"End date, or \"Present\" for current roles"},"yearsInCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsincompany"},"yearsInRole":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsinrole"},"jobDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescription"},"companyUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyurl","description":"Company LinkedIn URL for this position"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"companyId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyid","description":"LinkedIn company ID as a string, e.g. \"101088054\""},"companyLogo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylogo","description":"Company logo image URL (empty when unavailable)"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Where this role is based, e.g. \"Bordeaux, Nouvelle-Aquitaine, France\""},"employmentType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employmenttype","description":"Contract type as shown on the profile, e.g. \"Permanent\", \"Internship\""},"workplaceType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workplacetype","description":"Work arrangement, e.g. \"Hybrid\", \"Remote\", \"On-site\""}},"additionalProperties":true,"type":"object","title":"_PersonCompanyDetail","description":"One entry of currentCompanyDetail / pastCompaniesDetails (same shape)."},"type":"array"},{"type":"null"}],"title":"Currentcompanydetail"},"pastCompaniesDetails":{"anyOf":[{"items":{"properties":{"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"jobTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitle"},"startTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Starttime"},"endTime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endtime","description":"End date, or \"Present\" for current roles"},"yearsInCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsincompany"},"yearsInRole":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yearsinrole"},"jobDescription":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescription"},"companyUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyurl","description":"Company LinkedIn URL for this position"},"companyWebsite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companywebsite"},"companyId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyid","description":"LinkedIn company ID as a string, e.g. \"101088054\""},"companyLogo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylogo","description":"Company logo image URL (empty when unavailable)"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Where this role is based, e.g. \"Bordeaux, Nouvelle-Aquitaine, France\""},"employmentType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employmenttype","description":"Contract type as shown on the profile, e.g. \"Permanent\", \"Internship\""},"workplaceType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workplacetype","description":"Work arrangement, e.g. \"Hybrid\", \"Remote\", \"On-site\""}},"additionalProperties":true,"type":"object","title":"_PersonCompanyDetail","description":"One entry of currentCompanyDetail / pastCompaniesDetails (same shape)."},"type":"array"},{"type":"null"}],"title":"Pastcompaniesdetails"},"photoUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photourl"},"websites":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Websites","description":"Comma-separated personal website URLs"},"hiring":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hiring"},"registeredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Registeredat","description":"LinkedIn registration date (YYYY-MM-DD)"},"locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locale","description":"Profile locale, e.g. \"en\", \"fr\""}},"additionalProperties":true,"type":"object","title":"_PersonPerson","description":"The enriched LinkedIn person object (``data.person``)."},{"type":"null"}],"description":"The enriched person, or null if no match"}},"additionalProperties":true,"type":"object","title":"_PersonData","description":"``data`` wrapper for the person endpoints — holds a single ``person``."},{"type":"null"}],"description":"Matched person payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"ReverseEmailResponse","description":"Typed response for ``GET /enrichment/reverse-email``."},"example":{"data":{"person":{"firstName":"Marie","middleName":"","lastName":"Dupont","name":"Marie Dupont","linkedInUrl":"https://www.linkedin.com/in/marie-dupont","linkedInId":"251749025","linkedinSalesLink":"ACoAAB1exampleProfileUrnZ","headline":"VP Engineering at Lemlist","activeCompany":"Lemlist","numberOfCurrentCompanies":"1","location":"Paris, Île-de-France, France","country":"France","region":"Île-de-France","county":"Paris","city":"Paris","followers":"4821","followerCount":4821,"connectionsCount":500,"isCreator":false,"isJobSeeker":false,"isOpenLink":false,"isPremium":true,"isVerified":false,"openProfileMessages":true,"languages":"French, English","skillsList":"Python, Distributed Systems, Team Leadership","linkedinSummary":"Engineering leader focused on developer tooling and reliability.","companyWebsite":"https://lemlist.com","extractedGender":"","formerCompaniesList":"Datadog, Algolia","education":{"universitiesNamesList":"INSA Lyon","educationDetails":[{"startedOn":{"year":"2008"},"endedOn":{"year":"2013"},"universityName":"INSA Lyon","fieldsOfStudy":["Computer Science"],"socialUrl":"https://www.linkedin.com/company/15093/","schoolId":"15093","schoolLogo":"https://media.licdn.com/dms/image/v2/example/company-logo_400_400/0/1725378371996"}]},"certificationsList":"","certification":[],"currentCompanyDetail":[{"companyName":"Lemlist","jobTitle":"VP Engineering","startTime":"Mar-2021","endTime":"Present","yearsInCompany":"5 yrs","yearsInRole":"5 yrs","jobDescription":"","companyUrl":"https://www.linkedin.com/company/18394190/","companyWebsite":"https://lemlist.com","companyId":"18394190","companyLogo":"https://media.licdn.com/dms/image/v2/example/company-logo_400_400/0/1736784969376","location":"Paris, Ile-de-France, France","employmentType":"Permanent","workplaceType":"Hybrid"}],"pastCompaniesDetails":[{"companyName":"Datadog","jobTitle":"Staff Engineer","startTime":"2017","endTime":"Feb-2021","yearsInCompany":"4 yrs","yearsInRole":"4 yrs","companyUrl":"https://www.linkedin.com/company/1157/","companyWebsite":"https://datadoghq.com","companyId":"1157","companyLogo":"","location":"Paris, Ile-de-France, France","employmentType":"Permanent","workplaceType":"On-site"}],"photoUrl":"https://media.licdn.com/dms/image/v2/example/profile-displayphoto-shrink_800_800/0/1736826818808","websites":"https://mariedupont.dev","hiring":true,"registeredAt":"2009-04-12","locale":"en"}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"email","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/tech-stack":{"get":{"tags":["Enrichment"],"summary":"Get company tech stack","description":"Identify which technologies a company uses on their website—organized by category (frameworks, CDNs, analytics, email providers, etc.)—so you can understand their tech stack and build competitive intel.\n\n**Input:** company website `domain` (e.g., `lemlist.com`) OR `companyLinkedinUrl`.\n\n**Output:** `data` contains:\n- `companySearch` — the resolved company domain.\n- `techUsedList` — technologies grouped by category (e.g., \"Frameworks\", \"Content Delivery Network\", \"Analytics and Tracking\", \"JavaScript Libraries and Functions\"). Each category maps to a `values` array of detected technology names — for example, under \"Frameworks\" you might see `[\"React\", \"Next.js\"]`, and under \"Analytics and Tracking\" `[\"Google Analytics\", \"Segment\"]`. Categories vary per site, so iterate the object's keys rather than assuming a fixed set.\n\n**Cost:** 0.5 credits per successful result.","operationId":"enrichment_tech_stack_api_v1_enrichment_tech_stack_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company domain (e.g. google.com)","title":"Domain"},"description":"Company domain (e.g. google.com)"},{"name":"companyLinkedinUrl","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company LinkedIn URL","title":"Companylinkedinurl"},"description":"Company LinkedIn URL"}],"responses":{"200":{"description":"Detected technologies grouped by category.","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"companySearch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companysearch","description":"The domain or company that was looked up, e.g. 'lemlist.com'"},"techUsedList":{"anyOf":[{"additionalProperties":{"properties":{"values":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Values","description":"Detected technology names within this category"}},"additionalProperties":true,"type":"object","title":"_TechStackCategory","description":"Technologies detected within a single category."},"type":"object"},{"type":"null"}],"title":"Techusedlist","description":"Detected technologies grouped by category. Keys are category names; observed categories include: 'Content Delivery Network', 'Frameworks', 'JavaScript Libraries and Functions', 'Email Hosting Providers', 'Analytics and Tracking', 'Language', 'Web Servers', 'Programming Languages', 'CMS', 'Ecommerce', 'Advertising', 'Payment', 'Widgets', 'Security'. Each value is an object with a 'values' list of technology names."}},"additionalProperties":true,"type":"object","title":"_TechStackData"},{"type":"null"}],"description":"Tech-stack payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"TechStackResponse","description":"Typed response for the tech-stack enrichment endpoint."},"example":{"data":{"companySearch":"lemlist.com","techUsedList":{"Content Delivery Network":{"values":["Cloudflare","Amazon S3"]},"Frameworks":{"values":["React","Next.js","Open Graph"]},"JavaScript Libraries and Functions":{"values":["Webpack","core-js"]},"Email Hosting Providers":{"values":["Google Workspace","SPF","DMARC"]},"Analytics and Tracking":{"values":["Google Analytics","Segment"]},"Language":{"values":["English","French HREF LANG"]}}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/enrichment/validate-location":{"get":{"tags":["Enrichment"],"summary":"Validate a location filter value","description":"Validate a location name before you put it in a signal's `locations` or `excludedLocations` filter — so a typo fails fast here instead of silently producing a signal that matches no one.\n\n**Input:** `name` (query parameter) — a single country, region, or city name (e.g. `France`, `Île-de-France`, `Paris`). Optional `signalType` — set it to `job_offers`, `republished_job_offers` or `recruitment_campaign` when the name is for a job signal's `locations`: job postings are searched against their own place directory, so validate them against that one. A qualifier is understood — `Nantes (France)`, `Berlin, Germany` — and checked against the match.\n\n**Output:** `valid` (boolean — whether the name is recognized), `id` (the matched location's geo id, or null), `name` (the geo directory's label for the match — use it to confirm your input resolved to the place you meant; null when not recognized), and `message` (why it was rejected, present only when `valid` is false).\n\nSubmit the plain name you intend (never a geo id) in a signal's `locations` / `excludedLocations`; the filter matches on the name. Use this endpoint to catch two mistakes before writing a signal: an unrecognized name (`valid: false`), and a recognized-but-wrong match — e.g. `uk` matches `Ukraine`, so if you mean the United Kingdom, submit `United Kingdom`. The create and update endpoints reject any unrecognized name with a `400 INVALID_LOCATION` listing the offending values.","operationId":"validate_location_api_v1_enrichment_validate_location_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","description":"Location name to validate, e.g. 'France', 'Paris', 'Germany'.","examples":["Germany"],"title":"Name"},"description":"Location name to validate, e.g. 'France', 'Paris', 'Germany'."},{"name":"signalType","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional. The signal type the location is for. Pass `job_offers`, `republished_job_offers` or `recruitment_campaign` to validate a job signal's `locations` — job postings are searched against their own place directory, so a name can be valid for one and not the other.","examples":["job_offers"],"title":"Signaltype"},"description":"Optional. The signal type the location is for. Pass `job_offers`, `republished_job_offers` or `recruitment_campaign` to validate a job signal's `locations` — job postings are searched against their own place directory, so a name can be valid for one and not the other."}],"responses":{"200":{"description":"Validation result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationValidationResponse"},"examples":{"recognized":{"summary":"Recognized location","value":{"valid":true,"id":"101282230","name":"Germany"}},"unrecognized":{"summary":"Unrecognized location","value":{"valid":false,"message":"Location 'Frannce' not recognized"}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"name","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/enrichment/website-traffic":{"get":{"tags":["Enrichment"],"summary":"Get website traffic data","description":"Benchmark a company's web presence by analyzing their traffic volume, sources, and search performance.\n\n**Input:** provide `domain` (a company website domain, e.g. `lemlist.com`) or `companyLinkedinUrl` (a LinkedIn company URL).\n\n**Output:** traffic analytics in `data.siteOverview` — latest-month visit counts plus historical monthly-visit trends, bounce rate and engagement metrics (pages per visit, time on site), a traffic-source breakdown (share from direct, referrals, organic search, paid search, social, email, display ads, and other channels), top organic keywords driving traffic with search volume, CPC, and estimated value, global / country / category rankings, and page metadata (title, description, category).","operationId":"enrichment_website_traffic_api_v1_enrichment_website_traffic_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company domain (e.g. google.com)","title":"Domain"},"description":"Company domain (e.g. google.com)"},{"name":"companyLinkedinUrl","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Company LinkedIn URL","title":"Companylinkedinurl"},"description":"Company LinkedIn URL"}],"responses":{"200":{"description":"Traffic analytics (`data.siteOverview`).","content":{"application/json":{"schema":{"properties":{"data":{"anyOf":[{"properties":{"companySearch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companysearch","description":"The domain or company that was looked up, e.g. 'lemlist.com'"},"siteOverview":{"anyOf":[{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Site title / meta title"},"engagements":{"anyOf":[{"properties":{"visits":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visits","description":"Estimated monthly visits (numeric string)"},"bounceRate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bouncerate","description":"Bounce rate as a 0-1 fraction (numeric string), e.g. '0.4821'"},"pagePerVisit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pagepervisit","description":"Average pages viewed per visit (numeric string)"},"timeOnSite":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timeonsite","description":"Average time on site in seconds (numeric string)"},"month":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Month","description":"Month the snapshot covers (numeric string, 1-12)"},"year":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Year","description":"Year the snapshot covers (numeric string)"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficEngagements"},{"type":"null"}],"description":"Current-period engagement metrics"},"estimatedMonthlyVisits":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Estimatedmonthlyvisits","description":"Historical monthly visit estimates keyed by ISO date (first of month, 'YYYY-MM-DD'); values are numeric strings"},"globalRank":{"anyOf":[{"properties":{"rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rank","description":"Global traffic rank (lower is more visited)"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficGlobalRank"},{"type":"null"}]},"countryRank":{"anyOf":[{"properties":{"country":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Country","description":"Numeric country identifier"},"countryCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Countrycode","description":"ISO 3166-1 alpha-2 country code, e.g. 'FR', 'US'"},"rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rank","description":"Traffic rank within the country"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficCountryRank"},{"type":"null"}]},"categoryRank":{"anyOf":[{"properties":{"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Industry category slug, e.g. 'Computers_Electronics_and_Technology', 'Finance', 'E-commerce_and_Shopping', 'Business_and_Consumer_Services'"},"rank":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rank","description":"Traffic rank within the category (numeric string)"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficCategoryRank"},{"type":"null"}]},"trafficSources":{"anyOf":[{"properties":{"Direct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Direct","description":"Direct traffic share (0-1)"},"Referrals":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Referrals","description":"Referral traffic share (0-1)"},"SearchOrganic":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Searchorganic","description":"Organic search traffic share (0-1)"},"SearchPaid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Searchpaid","description":"Paid search traffic share (0-1)"},"SocialOrganic":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Socialorganic","description":"Organic social traffic share (0-1)"},"SocialPaid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Socialpaid","description":"Paid social traffic share (0-1)"},"Mail":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mail","description":"Email traffic share (0-1)"},"DisplayAds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Displayads","description":"Display advertising traffic share (0-1)"},"GenAi":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Genai","description":"Generative-AI referral traffic share (0-1)"},"Affiliate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Affiliate","description":"Affiliate traffic share (0-1)"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficTrafficSources","description":"Share of traffic by channel, each a 0-1 fraction summing to ~1.0."},{"type":"null"}]},"topKeywords":{"anyOf":[{"items":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Keyword phrase"},"volume":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Volume","description":"Estimated monthly search volume"},"cpc":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cpc","description":"Average cost-per-click for the keyword"},"estimatedValue":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimatedvalue","description":"Estimated monetary value of the organic traffic for this keyword"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficKeyword"},"type":"array"},{"type":"null"}],"title":"Topkeywords","description":"Top organic keywords driving traffic"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Lowercased industry category slug, e.g. 'computers_electronics_and_technology', 'finance', 'e-commerce_and_shopping', 'business_and_consumer_services'"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Short description of the site"},"isDataFromGa":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Isdatafromga","description":"Whether the metrics are sourced from the site's own analytics"},"snapshotDate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Snapshotdate","description":"ISO-8601 timestamp of the traffic snapshot"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficSiteOverview"},{"type":"null"}],"description":"Traffic analytics for the site, or null if unavailable"}},"additionalProperties":true,"type":"object","title":"_WebsiteTrafficData"},{"type":"null"}],"description":"Website traffic payload, or null if none found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"}},"additionalProperties":true,"type":"object","title":"WebsiteTrafficResponse","description":"Typed response for the website-traffic enrichment endpoint."},"example":{"data":{"companySearch":"lemlist.com","siteOverview":{"title":"lemlist - Sales engagement platform","engagements":{"visits":"1842110","bounceRate":"0.4821","pagePerVisit":"2.91","timeOnSite":"142.7","month":"5","year":"2026"},"estimatedMonthlyVisits":{"2026-03-01":"1693204","2026-04-01":"1771890","2026-05-01":"1842110"},"globalRank":{"rank":41207},"countryRank":{"country":250,"countryCode":"FR","rank":3120},"categoryRank":{"category":"Computers_Electronics_and_Technology","rank":"612"},"trafficSources":{"Direct":0.41203,"Referrals":0.12044,"SearchOrganic":0.33871,"SearchPaid":0.02011,"SocialOrganic":0.0721,"SocialPaid":0.00412,"Mail":0.00689,"DisplayAds":0.00302,"GenAi":0.01988,"Affiliate":0.0007},"topKeywords":[{"name":"lemlist","volume":201400,"cpc":4.12,"estimatedValue":214300},{"name":"cold email","volume":60300,"cpc":8.74,"estimatedValue":92100}],"category":"computers_electronics_and_technology","description":"Sales engagement platform for outbound teams.","isDataFromGa":false,"snapshotDate":"2026-05-01T00:00:00+00:00"}},"requestId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}},"400":{"description":"No search parameter supplied — provide at least one.","content":{"application/json":{"example":{"detail":{"error":{"code":"MISSING_PARAMETERS","message":"At least one search parameter is required."}}}}}}}}},"/api/v1/watchlists/sources":{"get":{"tags":["Watchlists"],"summary":"List the CRM lists a watchlist can be built from","description":"Build a watchlist from a list that already lives in your CRM, instead of sending the members inline — and keep the two in step as the segment moves.\n\n**Input:** `provider` — `hubspot` (default) or `pipedrive`.\n\n**Output:** `sources[]`, each with `sourceType` and `sourceListId` to pass straight into a watchlist's `config`, plus `name`, `size`, `watches` (`people` for a Job Change Watchlist, `companies` for the company watchlists) and `updatesItself` (true when the list is rule-based, so its membership changes on its own).\n\nAn empty array means that CRM is not connected to your account. Connecting one is an interactive authorisation and is done in the dashboard — this endpoint only reads what is already connected. A `412` means the connection exists but was granted without permission to read lists; reconnect it from the dashboard.\n\n**Use cases:**\n- Watch the champions in a closed-won list and hear the day one of them lands somewhere new — a warm introduction into a brand-new account.\n- Point a company watchlist at the target-account list your team already maintains, so the accounts you monitor never drift from the accounts you sell to.\n- Leave `sourceDynamicSync` on so a rule-based segment adds and removes watched records by itself, with no further API calls.","operationId":"list_watchlist_sources_api_v1_watchlists_sources_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"provider","in":"query","required":false,"schema":{"enum":["hubspot","pipedrive"],"type":"string","description":"Which connected CRM to read.","default":"hubspot","title":"Provider"},"description":"Which connected CRM to read."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"sources":{"items":{"properties":{"sourceType":{"type":"string","enum":["hubspot_list","pipedrive_filter"],"title":"Sourcetype","description":"Pass this as `sourceType` when creating a watchlist."},"sourceListId":{"type":"string","title":"Sourcelistid","description":"Pass this as `sourceListId`."},"name":{"type":"string","title":"Name","description":"The list's name in your CRM."},"watches":{"type":"string","enum":["people","companies"],"title":"Watches","description":"What the list holds. A people list feeds a Job Change Watchlist; a companies list feeds any of the company watchlists."},"size":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size","description":"How many records the list holds, when the CRM reports it."},"updatesItself":{"type":"boolean","title":"Updatesitself","description":"True when the list is rule-based, so its membership changes on its own. A hand-curated list only changes when someone edits it."}},"type":"object","required":["sourceType","sourceListId","name","watches","updatesItself"],"title":"WatchlistSource","description":"One CRM list a watchlist can be pointed at.","examples":[{"name":"Champions - closed won 2026","size":812,"sourceListId":"1274","sourceType":"hubspot_list","updatesItself":true,"watches":"people"}]},"type":"array","title":"Sources"}},"type":"object","required":["sources"],"title":"WatchlistSourceListResponse","examples":[{"sources":[{"name":"Champions - closed won 2026","size":812,"sourceListId":"1274","sourceType":"hubspot_list","updatesItself":true,"watches":"people"}]}]}}}},"412":{"description":"The CRM is connected but has not granted permission to read lists","content":{"application/json":{"example":{"error":{"code":"CRM_LIST_PERMISSION_MISSING","message":"Reconnect your CRM from the dashboard and grant list-read access."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"provider","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/watchlists/{signalId}/changes":{"get":{"tags":["Watchlists"],"summary":"List the job changes a watchlist has detected","operationId":"list_detected_changes_api_v1_watchlists__signalId__changes_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."},{"name":"confirmedOnly","in":"query","required":false,"schema":{"type":"boolean","description":"True (default) returns only changes confirmed as real job moves — the same set delivered to your webhook. False also returns candidate changes that were checked and dismissed (a headline edit, a reworded title), which is useful when auditing why someone produced no lead.","default":true,"title":"Confirmedonly"},"description":"True (default) returns only changes confirmed as real job moves — the same set delivered to your webhook. False also returns candidate changes that were checked and dismissed (a headline edit, a reworded title), which is useful when auditing why someone produced no lead."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"total":{"type":"integer","title":"Total"},"changes":{"items":{"properties":{"id":{"type":"string","title":"Id"},"detectedAt":{"type":"string","title":"Detectedat"},"changeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Changetype","description":"What changed: \"company\", \"title\", or \"both\"."},"previousTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previoustitle"},"previousCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previouscompany"},"newTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Newtitle"},"newCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Newcompany"},"leadId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Leadid","description":"Id of the lead this change produced, matching `contact.lead_id` in the webhook payload. Null when the change was detected but not confirmed as a real job change."}},"type":"object","required":["id","detectedAt"],"title":"DetectedChange","description":"One detected job change, as delivered to your webhook.","examples":[{"changeType":"company","detectedAt":"2026-08-04T09:12:00+00:00","id":"c3d4e5f6-a7b8-9012-cdef-345678901234","leadId":"b2c3d4e5-f6a7-8901-bcde-f23456789012","newCompany":"Doctolib","newTitle":"VP Marketing","previousCompany":"Payfit","previousTitle":"Head of Growth"}]},"type":"array","title":"Changes"}},"type":"object","required":["total","changes"],"title":"DetectedChangeListResponse"}}}},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"description":"Read the job changes a watchlist has already detected — to backfill a CRM from history, to reconcile against what your webhook received, or to work out why a watched person produced no lead.\n\n**Input:** `signalId` (path), plus optional `confirmedOnly` (default true — only real job moves, the same set delivered to your webhook; set false to also see candidate changes that were checked and dismissed, such as a headline edit or a reworded title), `limit` (1-500, default 100) and `offset`.\n\n**Output:** `total` and `changes` — each with `id`, `detectedAt`, `changeType` (`company`, `title`, or `both`), `previousTitle` / `previousCompany`, `newTitle` / `newCompany`, and `leadId` (matching `contact.lead_id` in the webhook payload, or null when the change was not confirmed).\n\nChanges are newest-first. A dismissed change with `leadId: null` is the answer to 'this person changed job, why did I get nothing' — the profile edit was judged not to be a real move."}},"/api/v1/watchlists/{signalId}/companies":{"get":{"tags":["Watchlists"],"summary":"List the companies a watchlist is watching","operationId":"list_watched_companies_api_v1_watchlists__signalId__companies_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"total":{"type":"integer","title":"Total"},"matched":{"type":"integer","title":"Matched","description":"Entries matched to a real employer and being checked."},"unmatched":{"type":"integer","title":"Unmatched","description":"Entries not currently being checked — the sum of `pending` and `notFound`. Reported so a half-working list is visible instead of looking like a list that simply is not hiring. Which of the two it is decides what to do about it, so read those two rather than this total."},"pending":{"type":"integer","title":"Pending","description":"Entries not looked up yet. A large list is worked through over successive passes; these need no action and resolve on their own."},"notFound":{"type":"integer","title":"Notfound","description":"Entries looked up with no matching employer. These will not resolve on their own — re-add them under their public trading name or their domain."},"companies":{"items":{"properties":{"id":{"type":"string","title":"Id","description":"Id of this entry — pass it to DELETE to stop watching."},"companyName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyname"},"companyDomain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companydomain"},"companyLinkedinUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companylinkedinurl"},"matched":{"type":"boolean","title":"Matched","description":"Whether this company is matched to a real employer and being checked for postings. `false` covers two different situations — read `resolutionStatus` to tell them apart before acting on it."},"resolutionStatus":{"type":"string","title":"Resolutionstatus","description":"Why this company is, or is not, being checked:\n\n- `resolved` - matched to an employer and being checked for postings.\n- `pending` - not looked up yet. A large list is worked through over successive passes, so a newly added company waits its turn. Nothing to fix.\n- `not_found` - looked up, and no employer matched the name supplied. This one will not resolve on its own: re-add the company under the name it trades under publicly (without the legal form), or under its domain."},"status":{"type":"string","title":"Status","description":"`active` (being checked) or `archived`."},"lastCheckedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastcheckedat"},"lastJobSeenAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastjobseenat","description":"Date of the most recent posting delivered for this company."}},"type":"object","required":["id","matched","resolutionStatus","status"],"title":"WatchedCompany","description":"One company on a job-offers watchlist.","examples":[{"companyDomain":"doctolib.fr","companyLinkedinUrl":"https://www.linkedin.com/company/doctolib","companyName":"Doctolib","id":"d4e5f6a7-b8c9-0123-def4-56789012345a","lastCheckedAt":"2026-08-04T09:12:00+00:00","lastJobSeenAt":"2026-08-03T00:00:00+00:00","matched":true,"resolutionStatus":"resolved","status":"active"}]},"type":"array","title":"Companies"}},"type":"object","required":["total","matched","unmatched","pending","notFound","companies"],"title":"WatchedCompanyListResponse","examples":[{"companies":[{"companyDomain":"doctolib.fr","companyLinkedinUrl":"https://www.linkedin.com/company/doctolib","companyName":"Doctolib","id":"d4e5f6a7-b8c9-0123-def4-56789012345a","lastCheckedAt":"2026-08-04T09:12:00+00:00","lastJobSeenAt":"2026-08-03T00:00:00+00:00","matched":true,"resolutionStatus":"resolved","status":"active"}],"matched":49,"notFound":51,"pending":100,"total":200,"unmatched":151}]}}}},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"description":"See which companies a Job Offers Watchlist is watching, and — crucially — which of them we could not match to a real employer, since those are silently never checked for postings.\n\n**Input:** `signalId` (path parameter).\n\n**Output:** `total`, `matched` (entries matched to a real employer and being checked), `unmatched` (entries that are not), and `companies` — each with `id` (pass it to DELETE), `companyName`, `companyDomain`, `companyLinkedinUrl`, `matched`, `status` (`active` or `archived`), `lastCheckedAt`, and `lastJobSeenAt` (the most recent posting delivered for that company).\n\nCheck `unmatched` first when a watchlist delivers less than you expected: an unmatched company looks identical to a company that simply is not hiring. Fix one by re-adding it under a different spelling of its name, or by its domain."},"post":{"tags":["Watchlists"],"summary":"Add companies to a watchlist","operationId":"add_watched_companies_api_v1_watchlists__signalId__companies_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":10000,"minItems":1,"title":"Companies","description":"Companies to watch. Each entry is either a plain string — a name (`\"Doctolib\"`), a domain (`\"doctolib.fr\"`) or a LinkedIn company URL — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company. Both forms can be mixed. Send every identifier you have: the LinkedIn URL identifies the company exactly, and entries naming the same company are merged into one.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved."},"mode":{"type":"string","enum":["append","replace"],"title":"Mode","description":"`append` (default) adds these to the list. `replace` makes this the whole list: companies not in it stop being checked.","default":"append"}},"type":"object","required":["companies"],"title":"AddCompaniesRequest","examples":[{"companies":["Doctolib","payfit.com",{"domain":"alan.com","linkedinUrl":"https://www.linkedin.com/company/alan-eu","name":"Alan"}],"mode":"append"}]}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"added":{"type":"integer","title":"Added","description":"Entries now being watched that were not before."},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on the list, left unchanged.","default":0},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — not a valid identifier for this list.","default":0},"stoppedWatching":{"type":"integer","title":"Stoppedwatching","description":"Entries dropped because `mode` was `replace`. Always 0 on `append`.","default":0},"totalWatched":{"type":"integer","title":"Totalwatched","description":"Entries being watched after this call."}},"type":"object","required":["added","totalWatched"],"title":"WatchlistMutationResponse","description":"What a list change actually did.\n\nEvery outcome is reported separately because they mean different things to\nthe caller: `rejected` is input to fix, `alreadyWatched` is a no-op, and\n`stoppedWatching` is people who dropped off a `replace`.","examples":[{"added":2,"alreadyWatched":1,"rejected":0,"stoppedWatching":0,"totalWatched":43}]}}}},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"description":"Add companies to a Job Offers Watchlist without recreating the signal — extend the list as your target-account list grows, or replace it when the quarter's territory changes.\n\n**Input:** `signalId` (path), `companies` (array of 1 to 10,000 names, domains or LinkedIn company URLs), and `mode`: `append` (default) or `replace` (companies not in the list stop being checked).\n\nEach entry is either a plain string or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company, e.g. `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Strings and objects can be mixed in one call, and entries naming the same company are merged into one watched company carrying all their identifiers.\n\n**Send the LinkedIn company URL whenever you have it.** It identifies the company exactly; a name does not, and two companies sharing a name cannot be told apart from the name alone — the list will look fully matched while watching the wrong one. A name still matches more reliably than a domain, so send the name when the URL is not available. Re-sending a company with its URL added corrects a match made earlier from its name.\n\n**Output:** `added`, `alreadyWatched` (already on the list, details refreshed), `rejected` (neither a usable name nor a domain), `stoppedWatching` (dropped by a `replace`), and `totalWatched`.\n\nA company added here is matched to a real employer on its first check, not immediately — call `GET /companies` afterwards and read `unmatched` to confirm the list is fully covered. Its first check only looks back over the signal's `firstRunLookbackDays`, so adding a company does not dump its whole posting history on you."}},"/api/v1/watchlists/{signalId}/companies/confirm-matching":{"post":{"tags":["Watchlists"],"summary":"Quote and confirm the matching of a watchlist's companies","operationId":"confirm_watchlist_matching_api_v1_watchlists__signalId__companies_confirm_matching_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"confirm":{"type":"boolean","title":"Confirm","description":"`true` confirms the cost quoted for matching this watchlist's companies and starts the matching. `false` (default) only returns the quote.","default":false}},"type":"object","title":"ConfirmMatchingRequest","examples":[{"confirm":true}]}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"status":{"type":"string","enum":["nothing_to_match","awaiting_confirmation","insufficient_credits","confirmed"],"title":"Status","description":"`confirmed`: matching runs (or needs no confirmation). `awaiting_confirmation`: nothing is matched or charged until you call this endpoint with `confirm: true`. `insufficient_credits`: your balance does not cover `estimatedCost`; top up, then confirm. `nothing_to_match`: every company is already matched."},"companiesToMatch":{"type":"integer","title":"Companiestomatch","description":"Companies not yet matched."},"alreadyMatchedFree":{"type":"integer","title":"Alreadymatchedfree","description":"Of those, companies we have already matched before: free."},"billableCompanies":{"type":"integer","title":"Billablecompanies"},"pricePerCompany":{"type":"number","title":"Pricepercompany"},"currency":{"type":"string","enum":["credits","eur"],"title":"Currency","description":"The unit of `pricePerCompany` and `estimatedCost`."},"estimatedCost":{"type":"number","title":"Estimatedcost","description":"At most this much is charged: a company is charged only once it is matched."},"isUpperBound":{"type":"boolean","title":"Isupperbound","default":true},"sufficientBalance":{"type":"boolean","title":"Sufficientbalance"},"confirmationRequired":{"type":"boolean","title":"Confirmationrequired","description":"True when the cost is above the amount we match without asking."}},"type":"object","required":["status","companiesToMatch","alreadyMatchedFree","billableCompanies","pricePerCompany","currency","estimatedCost","sufficientBalance","confirmationRequired"],"title":"MatchingQuoteResponse","description":"What matching this watchlist's companies costs, and whether it may start.","examples":[{"alreadyMatchedFree":8880,"billableCompanies":40612,"companiesToMatch":49492,"confirmationRequired":true,"currency":"credits","estimatedCost":2030.6,"isUpperBound":true,"pricePerCompany":0.05,"status":"confirmed","sufficientBalance":true}]}}}},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"description":"See what it costs to start watching a large company list, and say yes — for a New Decision Maker or Account watchlist whose list you sent through the API or synced from HubSpot.\n\nBefore a company can be watched for new decision makers it is matched to its LinkedIn company page, and each match is billed. A small list is matched straight away; above a set amount nothing is matched or charged until you confirm, and the signal's `warnings` carry `MATCHING_CONFIRMATION_REQUIRED` with the quote. You are also told without asking: the account owners get an email with the quote and a link to confirm in the dashboard, and the signal's `webhookUrl` receives a `signal.action_required` event.\n\n**Input:** `signalId` (path) and `confirm`: `false` (default) returns the quote only, `true` accepts it and starts the matching.\n\n**Output:** `status` (`awaiting_confirmation`, `confirmed`, `insufficient_credits` or `nothing_to_match`), `companiesToMatch`, `alreadyMatchedFree` (companies matched before, free), `billableCompanies`, `pricePerCompany`, `currency`, `estimatedCost` (an upper bound — a company is charged only once it is matched), `sufficientBalance` and `confirmationRequired`.\n\nSend the LinkedIn company URL of each company when you have it: it is matched exactly, and a numeric company URL (`/company/1234567`) is already matched and never billed."}},"/api/v1/watchlists/{signalId}/companies/{companyId}":{"delete":{"tags":["Watchlists"],"summary":"Stop watching one company","description":"Stop watching one company — for an account you have closed, churned, or disqualified.\n\n**Input:** `signalId` and `companyId` (both path parameters). `companyId` is the `id` from `GET /companies`.\n\n**Output:** `204 No Content`.\n\nThe entry is archived rather than deleted, so the date of the last posting we delivered for it survives. Re-adding the company later resumes from there instead of re-delivering every posting you have already received.","operationId":"remove_watched_company_api_v1_watchlists__signalId__companies__companyId__delete","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."},{"name":"companyId","in":"path","required":true,"schema":{"type":"string","description":"Entry id from GET /companies.","examples":["d4e5f6a7-b8c9-0123-def4-56789012345a"],"title":"Companyid"},"description":"Entry id from GET /companies."}],"responses":{"204":{"description":"Successful Response"},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}},"/api/v1/watchlists/{signalId}/profiles":{"get":{"tags":["Watchlists"],"summary":"List the people a watchlist is watching","operationId":"list_watched_profiles_api_v1_watchlists__signalId__profiles_get","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"enum":["active","archived","error"],"type":"string"},{"type":"null"}],"description":"Filter by entry state. Omit to get every entry.","title":"Status"},"description":"Filter by entry state. Omit to get every entry."},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Case-insensitive match on name, email, employer, or profile URL.","title":"Search"},"description":"Case-insensitive match on name, email, employer, or profile URL."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"total":{"type":"integer","title":"Total","description":"Entries matching the filter, ignoring pagination."},"profiles":{"items":{"properties":{"id":{"type":"string","title":"Id","description":"Id of this entry — pass it to DELETE to stop watching."},"linkedinUrl":{"type":"string","title":"Linkedinurl"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"currentTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currenttitle","description":"Title as of the last check — the baseline the next check compares against."},"currentCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currentcompany","description":"Employer as of the last check."},"status":{"type":"string","title":"Status","description":"`active` (being checked), `archived` (removed from the list, kept for history), or `error` (the profile could not be read repeatedly)."},"lastCheckedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastcheckedat","description":"When this person was last checked. Null until the first check runs."}},"type":"object","required":["id","linkedinUrl","status"],"title":"WatchedProfile","description":"One person on a job-change watchlist.","examples":[{"currentCompany":"Payfit","currentTitle":"Head of Growth","email":"marie.dupont@payfit.com","firstName":"Marie","id":"b2c3d4e5-f6a7-8901-bcde-f23456789012","lastCheckedAt":"2026-08-04T09:12:00+00:00","lastName":"Dupont","linkedinUrl":"https://www.linkedin.com/in/marie-dupont","status":"active"}]},"type":"array","title":"Profiles"}},"type":"object","required":["total","profiles"],"title":"WatchedProfileListResponse"}}}},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"description":"See exactly who a Job Change Watchlist is watching, and what role each person was last seen in — so you can confirm the list you sent is the list being checked before you wait a week for changes that were never going to come.\n\n**Input:** `signalId` (path — the watchlist signal's id), plus optional `status` (`active`, `archived`, or `error`; omit for all), `search` (case-insensitive match on name, email, employer, or profile URL), `limit` (1-500, default 100) and `offset`.\n\n**Output:** `total` (entries matching the filter, ignoring pagination) and `profiles` — each with `id` (pass it to DELETE), `linkedinUrl`, `firstName` / `lastName` / `email`, `currentTitle` and `currentCompany` (the baseline the next check compares against), `status`, and `lastCheckedAt` (null until the first check runs).\n\nTwo states are worth acting on: `error` means the profile could not be read repeatedly and is producing nothing, and a `currentCompany` that is still null long after `lastCheckedAt` was set means we could not read that person's employer, so an employer change cannot be detected for them."},"post":{"tags":["Watchlists"],"summary":"Add people to a watchlist","operationId":"add_watched_profiles_api_v1_watchlists__signalId__profiles_post","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"profiles":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedProfileSeed"}]},"type":"array","maxItems":10000,"minItems":1,"title":"Profiles","description":"People to watch. Each entry is either a LinkedIn profile URL on its own, or an object carrying the role you already have on file — send the object form when you can, because it is what lets the first check report a change instead of only recording a starting point. The two forms can be mixed in one call. Country subdomains and tracking query strings are accepted and normalized; anything that is not a personal profile URL is counted in `rejected` rather than failing the request."},"mode":{"type":"string","enum":["append","replace"],"title":"Mode","description":"`append` (default) adds these people to the list and leaves everyone else in place. `replace` makes this the whole list: anyone not in it stops being watched. Their history is kept either way.","default":"append"}},"type":"object","required":["profiles"],"title":"AddProfilesRequest","examples":[{"mode":"append","profiles":[{"currentCompany":"Doctolib","currentTitle":"VP Sales","url":"https://www.linkedin.com/in/marie-dupont"},"https://www.linkedin.com/in/jean-martin"]}]}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"added":{"type":"integer","title":"Added","description":"Entries now being watched that were not before."},"alreadyWatched":{"type":"integer","title":"Alreadywatched","description":"Entries already on the list, left unchanged.","default":0},"rejected":{"type":"integer","title":"Rejected","description":"Entries that could not be used — not a valid identifier for this list.","default":0},"stoppedWatching":{"type":"integer","title":"Stoppedwatching","description":"Entries dropped because `mode` was `replace`. Always 0 on `append`.","default":0},"totalWatched":{"type":"integer","title":"Totalwatched","description":"Entries being watched after this call."}},"type":"object","required":["added","totalWatched"],"title":"WatchlistMutationResponse","description":"What a list change actually did.\n\nEvery outcome is reported separately because they mean different things to\nthe caller: `rejected` is input to fix, `alreadyWatched` is a no-op, and\n`stoppedWatching` is people who dropped off a `replace`.","examples":[{"added":2,"alreadyWatched":1,"rejected":0,"stoppedWatching":0,"totalWatched":43}]}}}},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}},"description":"Add people to a Job Change Watchlist without recreating the signal — grow the list as you win new champions, or swap it wholesale when your CRM segment changes.\n\n**Input:** `signalId` (path), `profiles` (1 to 10,000 entries), and `mode`: `append` (default — adds these and leaves everyone else in place) or `replace` (makes this the whole list; anyone not in it stops being watched, with their history kept).\n\nEach entry in `profiles` is either a LinkedIn profile URL on its own, or an object `{url, currentTitle, currentCompany, currentCompanyUrl}` carrying the role you already have on file. Both forms can be mixed in one call. Country subdomains and tracking query strings are accepted and normalized.\n\n**Send the role you have.** Every check is billed, the first one included. With a role on file, the first check compares against it and reports any change straight away. With a bare URL, the first check can only report a move made in the last 6 months (it compares the current job with the one before it); anyone who moved earlier stays invisible, recorded as they stand today, and a later move is reported at the next check, one `cadenceHours` later. Either field helps on its own — `currentCompany` catches an employer change, `currentTitle` catches a promotion.\n\nOne watchlist holds at most 40,000 people. That is a limit on the list, not on the request: send a larger list as successive `append` calls of up to 10,000, and the call that would take the list past 40,000 is rejected with 400.\n\n**Output:** `added` (now watched, were not before), `alreadyWatched` (already on the list, unchanged), `rejected` (not a usable personal profile URL), `stoppedWatching` (dropped by a `replace`; always 0 on `append`), and `totalWatched` (the size of the list after this call).\n\nA bad URL never fails the request — it is counted in `rejected` so one typo in a 500-person list does not reject the other 499. Check `rejected` against what you sent. Re-adding someone previously removed resumes their history rather than reporting their current role as a fresh change."}},"/api/v1/watchlists/{signalId}/profiles/{profileId}":{"delete":{"tags":["Watchlists"],"summary":"Stop watching one person","description":"Stop watching one person — for when a champion leaves your ICP, or you are trimming a list down to the accounts you actually sell to.\n\n**Input:** `signalId` and `profileId` (both path parameters). `profileId` is the `id` from `GET /profiles`, not the LinkedIn URL.\n\n**Output:** `204 No Content`.\n\nThe entry is archived rather than deleted: its detected-change history stays readable via `GET /changes`, and re-adding the same person later resumes from that history instead of reporting their current role as a brand-new change.","operationId":"remove_watched_profile_api_v1_watchlists__signalId__profiles__profileId__delete","security":[{"BearerAuth":[]}],"parameters":[{"name":"signalId","in":"path","required":true,"schema":{"type":"string","description":"Id of the watchlist signal, as returned by the create endpoint.","examples":["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],"title":"Signalid"},"description":"Id of the watchlist signal, as returned by the create endpoint."},{"name":"profileId","in":"path","required":true,"schema":{"type":"string","description":"Entry id from GET /profiles (not the LinkedIn URL).","examples":["b2c3d4e5-f6a7-8901-bcde-f23456789012"],"title":"Profileid"},"description":"Entry id from GET /profiles (not the LinkedIn URL)."}],"responses":{"204":{"description":"Successful Response"},"404":{"description":"No watchlist signal with this id on your account","content":{"application/json":{"example":{"error":{"code":"NOT_FOUND","message":"No watchlist signal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}}},"400":{"description":"The signal exists but watches the other kind of subject","content":{"application/json":{"example":{"error":{"code":"WRONG_WATCHLIST_KIND","message":"This signal watches companies, not people. Use the /companies endpoints instead."}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"error":{"code":"VALIDATION_ERROR","message":"Validation failed: Field required","details":{"field":"signalId","message":"Field required"}}}}}},"429":{"description":"Rate limit exceeded. Retry after the number of seconds in the `Retry-After` response header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests"}}}}}}}}},"components":{"schemas":{"AccountWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"sources":{"additionalProperties":{"$ref":"#/components/schemas/AccountWatchlistSource"},"type":"object","title":"Sources","description":"Which events to watch for, keyed by source. Omit for the defaults. Keys: `fundraising`, `mergers_acquisitions`, `forecasted_funding`, `forecasted_ipo`, `forecasted_acquisition`, `forecasted_growth`, `public_tenders`, `job_offers`, `recruitment_campaign`, `new_decision_makers`, `company_post_reactions`, `competitor_social_reactions`, `competitor_connections`, `company_news`. `company_news` is off unless you switch it on."},"firstRunLookbackDays":{"type":"integer","maximum":365.0,"minimum":1.0,"title":"Firstrunlookbackdays","description":"How far back the FIRST check reaches. Matching events from that window are delivered immediately, so an uploaded list is worth something the same day; later checks deliver only what is new. Bounded because an unbounded first run would bill you for years of history the moment you save.","default":180}},"type":"object","title":"AccountWatchlistConfig","description":"Config for account_watchlist — one list, every event we can watch for on a company.\n\nUpload the accounts once and hear about everything that happens to them.\nEach event you switch on is delivered as an ordinary lead, billed at ONE flat\nrate whichever event produced it — never at the rate of the underlying event\ntype, so a funding lead and a job lead cost the same here.\n\n``sources`` is a map of source key to ``{\"enabled\": bool}``, plus any\nper-source override you want to set. Leave it out and every event is watched;\nsend it only to switch some off.\n\n``dailyLeadLimit`` on the signal is ONE budget for everything the watchlist\nproduces — not one per event.","examples":[{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"firstRunLookbackDays":180,"getEmails":true,"sources":{"competitor_connections":{"enabled":false},"fundraising":{"enabled":true},"job_offers":{"enabled":true},"mergers_acquisitions":{"enabled":true},"new_decision_makers":{"enabled":true}},"targetPersonas":["sales_leadership"]}]},"AccountWatchlistSource":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"Whether this source produces leads","default":true},"filters":{"anyOf":[{"$ref":"#/components/schemas/AccountWatchlistSourceFilters"},{"type":"null"}],"description":"Per-source override — see AccountWatchlistSourceFilters. Omit to inherit the umbrella-wide targeting below for this source."}},"additionalProperties":true,"type":"object","title":"AccountWatchlistSource","description":"One source toggled on an account watchlist."},"AccountWatchlistSourceFilters":{"properties":{"targetPersonas":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"customPersonaTitles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Excludedtitles","description":"Job titles to exclude from results"},"customJobTitles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Customjobtitles","description":"new_decision_makers only: extra titles alongside targetPersonas"},"locations":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Locations","description":"company_post_reactions / competitor_social_reactions / competitor_connections only: the PERSON's location"},"excludedLocations":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Excludedlocations","description":"Locations to exclude from results"},"jobTitleInclude":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Jobtitleinclude","description":"job_offers only: keywords the job title must include"},"jobTitleExclude":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Jobtitleexclude","description":"job_offers only: keywords the job title must not include"}},"additionalProperties":true,"type":"object","title":"AccountWatchlistSourceFilters","description":"A per-source override — narrows ONE source without touching the\numbrella-wide targeting every other source still inherits.\n\nEvery field here is optional and defaults to inheriting the umbrella's\nown setting; set a field to override it for THIS source only, or to\n`[]` to clear it to \"match anything\". Which fields apply depends on the\nsource (see `GET /api/v1/watchlists/{signalId}/tracked-events` ->\n`filterKeys` for the live list per source on your signal):\n\n- `new_decision_makers`: `targetPersonas`, `customJobTitles`, `excludedTitles`\n- `job_offers`: `jobTitleInclude`, `jobTitleExclude`, `targetPersonas`\n- `company_post_reactions`, `competitor_social_reactions`,\n  `competitor_connections`: `targetPersonas`, `customPersonaTitles`,\n  `excludedTitles`, `locations`, `excludedLocations` (the PERSON's\n  location, not the company's — the company is already fixed by your\n  list)\n- `fundraising`, `mergers_acquisitions`, the four `forecasted_*` sources,\n  `public_tenders`, `company_news`: `targetPersonas`,\n  `customPersonaTitles`, `excludedTitles`\n\nA field a source does not support is refused (422\n`FILTER_NOT_SUPPORTED_FOR_SOURCE`), never silently ignored.","examples":[{"excludedTitles":["Stagiaire"],"targetPersonas":["Sales Director"]}]},"CompanyEngagementConfig":{"properties":{"postedLimit":{"type":"string","title":"Postedlimit","description":"Time window (default \"week\" for engagement)","default":"week"},"minEngagement":{"type":"integer","title":"Minengagement","description":"Minimum engagement count","default":5},"maxPosts":{"type":"integer","title":"Maxposts","description":"Max posts to process (0 = unlimited)","default":0},"engagementTypes":{"items":{"type":"string","enum":["likes","comments","poster","both"]},"type":"array","title":"Engagementtypes","description":"Which people on each surfaced post become leads. Combine the values in this array:\n- \"likes\": people who reacted to the post.\n- \"comments\": people who commented on the post.\n- \"poster\": the post author. Use [\"poster\"] alone for an author-only signal (no engager fan-out — typically much less noise).\n- \"both\": intersection of likes AND comments (highest intent, smallest volume).\nExamples: [\"likes\", \"comments\"] = union (reacted OR commented); [\"poster\"] = author only; [\"poster\", \"comments\"] = author + commenters.","default":["likes","comments"]},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"linkedinUrls":{"items":{"type":"string"},"type":"array","title":"Linkedinurls","description":"LinkedIn profile URLs to track engagement on"}},"type":"object","title":"CompanyEngagementConfig","description":"Config for company_engagement (Influencer Post Reactions — profile URLs\nonly). Delivers people who ENGAGED WITH the posts of the person(s) you list\nhere — not the listed person themselves going quiet; that is\n`dormant_linkedin_poster`, a different signal type with its own ICP-based\ntargeting rather than a list of URLs."},"CompanyFollowersConfig":{"properties":{"restrictToCompanies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","title":"Restricttocompanies","description":"Only deliver leads at these companies. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company; both forms can be mixed. The more identifiers you send, the more of your list is recognised. Matching is exact once punctuation and legal suffixes are ignored. Consumed on create, so it is NOT echoed back in `config`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/companies`.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved."},"restrictToProfiles":{"items":{"type":"string"},"type":"array","title":"Restricttoprofiles","description":"Only deliver leads for these people — LinkedIn profile URLs. Consumed on create like `restrictToCompanies`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/profiles`."},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"mode":{"type":"string","title":"Mode","description":"Collection mode: \"saved_search\" or \"csv_import\"","default":"saved_search"},"extractionMode":{"type":"string","enum":["count","icp"],"title":"Extractionmode","description":"How followers are pulled: \"count\" extracts a fixed number of followers unfiltered; \"icp\" extracts all followers matching the persona / company-size / location filters.","default":"icp"},"linkedinCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Linkedincompanyurls","description":"LinkedIn company URLs to track followers"},"targetCompanies":{"items":{"type":"string"},"type":"array","title":"Targetcompanies","description":"LinkedIn company URLs of the employers to keep. Followers are kept only when they currently work at one of these companies — use it to watch a competitor's audience for the accounts you already sell to. Applies to ICP extraction only; max 50."},"salesNavSearchUrl":{"type":"string","title":"Salesnavsearchurl","description":"Sales Navigator search URL","default":""},"dailyExtractLimit":{"type":"integer","title":"Dailyextractlimit","description":"Max profiles to extract per day","default":100},"lastExtractedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastextractedat","description":"Timestamp of last extraction"},"autoQuote":{"type":"boolean","title":"Autoquote","description":"`extractionMode: \"icp\"` only. `true` requests the extraction quote for you as soon as the signal is `active` (at creation, or when you activate it or set this later), instead of calling POST /api/v1/signals/{signal_id}/extraction/quote yourself. Requesting a quote is free. It is accepted automatically only when it is within `maxCredits`; otherwise it stays open for you to accept, and the signal carries a `QUOTE_REQUIRED` warning with the price. Default `false`.","default":false},"maxCredits":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Maxcredits","description":"With `autoQuote`: the most credits an automatically requested quote may cost and still be accepted for you (accepting holds that amount; you are charged for the leads delivered). A quote above it is left open for you to accept or decline. Omitted or `null`: the quote is requested but never accepted automatically."},"extractionLimit":{"type":"integer","title":"Extractionlimit","description":"`extractionMode: \"count\"` only: how many followers to extract, unfiltered (the first `extractionLimit` followers of the pages). Minimum 100: a lower value is refused with `422` and `error.code` `EXTRACTION_LIMIT_TOO_LOW`. Default 500.","default":500}},"type":"object","title":"CompanyFollowersConfig","description":"Config for company_followers."},"CompanyFollowersCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/CompanyFollowersConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft)."}},"type":"object","required":["name","config"],"title":"CompanyFollowersCreate","examples":[{"config":{"getEmails":true,"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist"],"locations":["France"],"targetPersonas":["HR Director"]},"dailyLeadLimit":50,"name":"Followers of a competitor page (FR, HR personas)","status":"draft","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"CompanyGrowthConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Countries / regions to target (e.g. France)"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company sizes to include (51-200, 201-500, ...)"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Industries to target. Use industry names from GET /api/v1/signals/industries — the entries with `kind: \"industry\"`, e.g. 'Software Development'. Unlike the other signals, this one resolves each name to a LinkedIn industry id, so a `kind: \"category\"` name does NOT expand to the industries inside it: 9 of the 19 categories resolve to nothing at all and are dropped, and the other 10 narrow to the single same-named industry. A name that does not resolve is skipped silently, so copy values verbatim. Empty = all industries."},"growthMin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Growthmin","description":"Signed headcount-growth floor % (negative = shrinking)"},"growthMax":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Growthmax","description":"Signed headcount-growth ceiling %"}},"additionalProperties":true,"type":"object","title":"CompanyGrowthConfig","description":"Config for company_growth — company headcount trajectory.\n\nInherits PersonaTargetingConfig so the enable_persona_lookup ->\nenable_persona_targeting mapping runs (persona targeting is the whole point).\nextra=\"allow\" preserves infra fields (daily_lead_limit) read raw by the task."},"CompanyNewsWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"eventTypes":{"items":{"type":"string"},"type":"array","title":"Eventtypes","description":"Event types to deliver: `funding`, `mergers_acquisitions`, `expansion`, `leadership_change`, `product_launch`, `contract_partnership`, `restructuring`, `event_participation` (an upcoming trade show or conference the company will exhibit or speak at). Empty = every type except `event_participation`, which is delivered only when you list it."},"maxEventAgeDays":{"type":"integer","maximum":365.0,"minimum":1.0,"title":"Maxeventagedays","description":"Only deliver events that happened in the last N days (1-365). Also sets how far back the first check of a newly added company looks.","default":90},"cadenceDays":{"type":"integer","maximum":90.0,"minimum":14.0,"title":"Cadencedays","description":"How often each company is checked for new events, in days (14-90, default 30). Shorter means events reach you sooner.","default":30}},"type":"object","title":"CompanyNewsWatchlistConfig","description":"Config for company_news_watchlist: business events at the companies you name.\n\nEach watched company is checked on a regular cadence for news about it:\nfunding, acquisitions and mergers, new locations or expansion, leadership\nchanges, product launches, contracts or partnerships, layoffs or\nrestructuring, and upcoming trade shows or conferences it will exhibit or\nspeak at. An event is delivered only when the article is about that exact\ncompany, its date is read from the article itself and falls inside your\nwindow (a trade show must still be ahead), and it matches a type you asked\nfor. The same event reported by several outlets is delivered once.","examples":[{"cadenceDays":30,"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"eventTypes":["funding","mergers_acquisitions","leadership_change"],"getEmails":true,"maxEventAgeDays":90}]},"CompanyPostReactionsConfig":{"properties":{"postedLimit":{"type":"string","title":"Postedlimit","description":"Time window (default \"week\" for reactions)","default":"week"},"minEngagement":{"type":"integer","title":"Minengagement","description":"Minimum engagement count","default":5},"maxPosts":{"type":"integer","title":"Maxposts","description":"Max posts to process (0 = unlimited)","default":0},"engagementTypes":{"items":{"type":"string","enum":["likes","comments","poster","both"]},"type":"array","title":"Engagementtypes","description":"Which people on each surfaced post become leads. Combine the values in this array:\n- \"likes\": people who reacted to the post.\n- \"comments\": people who commented on the post.\n- \"poster\": the post author. Use [\"poster\"] alone for an author-only signal (no engager fan-out — typically much less noise).\n- \"both\": intersection of likes AND comments (highest intent, smallest volume).\nExamples: [\"likes\", \"comments\"] = union (reacted OR commented); [\"poster\"] = author only; [\"poster\", \"comments\"] = author + commenters.","default":["likes","comments"]},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"linkedinCompanyUrls":{"items":{"type":"string"},"type":"array","maxItems":15000,"title":"Linkedincompanyurls","description":"LinkedIn company page URLs to track post reactions on (max 15000)"}},"type":"object","title":"CompanyPostReactionsConfig","description":"Config for company_post_reactions (Company Post Reactions — company page\nURLs only). Delivers people who reacted to posts PUBLISHED BY the company\npage(s) you list here. For a company's EMPLOYEES rather than its page, see\n`competitor_social_reactions`. For a poster who has gone dormant, see\n`dormant_linkedin_poster` — a separate signal type, not an option here."},"CompanyRegistrationConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"nafCodes":{"items":{"type":"string"},"type":"array","title":"Nafcodes","description":"NAF activity codes to filter (e.g. \"62.01Z\" for programming)"},"departmentCodes":{"items":{"type":"string"},"type":"array","title":"Departmentcodes","description":"French department codes to filter (e.g. \"75\", \"69\")"},"regionCodes":{"items":{"type":"string"},"type":"array","title":"Regioncodes","description":"French region codes for SIRENE region param (e.g. \"11\" for Île-de-France)"},"legalForms":{"items":{"type":"string"},"type":"array","title":"Legalforms","description":"INSEE nature_juridique codes to filter (e.g. \"5710\" for SAS, \"5499\" for SARL)"},"employeeSizeCodes":{"items":{"type":"string"},"type":"array","title":"Employeesizecodes","description":"SIRENE tranche_effectif_salarie codes (e.g. \"01\" for 1-2, \"12\" for 20-49)"}},"type":"object","title":"CompanyRegistrationConfig","description":"Config for company_registration (new French company registrations from SIRENE)."},"CompetitorRelationshipCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/LinkedInConnectionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"CompetitorRelationshipCreate","description":"Create a Competitor Connections signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500","501-1000"],"customPersonaTitles":["VP of Growth","Chief Revenue Officer"],"detectTechnologies":false,"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedCompanyUrls":[],"excludedIndustryFilters":["Financial Services"],"excludedLocations":["Paris"],"excludedTitles":["Intern","Junior"],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"industryFilters":["Technology, Information and Internet","Software Development"],"linkedinCompanyUrls":["https://www.linkedin.com/company/lemlist","https://www.linkedin.com/company/la-growth-machine"],"locations":["France"],"targetPersonas":["Sales Director","Marketing Director"]},"dailyLeadLimit":50,"name":"Tech competitors in France","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"CompetitorSocialReactionsConfig":{"properties":{"postedLimit":{"type":"string","title":"Postedlimit","description":"Time window for surfacing reactions (default \"week\")","default":"week"},"minEngagement":{"type":"integer","title":"Minengagement","description":"Minimum engagement count","default":5},"maxPosts":{"type":"integer","title":"Maxposts","description":"Max posts to process (0 = unlimited)","default":0},"engagementTypes":{"items":{"type":"string","enum":["likes","comments","poster","both"]},"type":"array","title":"Engagementtypes","description":"Which people on each surfaced post become leads. Defaults to [\"poster\", \"likes\", \"comments\"]: the post author plus everyone who liked or commented. Combine the values:\n- \"poster\": the post author — the person whose content the competitor's GTM team engaged with. Use [\"poster\"] alone for an author-only signal (no engager fan-out).\n- \"likes\": people who reacted to the post.\n- \"comments\": people who commented on the post.\n- \"both\": intersection of likes AND comments (highest intent, smallest volume).\nExamples: [\"poster\"] = author only; [\"likes\", \"comments\"] = engagers only (no author); [\"poster\", \"both\"] = author + dual-engagers.","default":["poster","likes","comments"]},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"linkedinCompanyUrls":{"items":{"type":"string"},"type":"array","maxItems":15000,"title":"Linkedincompanyurls","description":"LinkedIn company URLs of the competitors to monitor (max 15000)"}},"type":"object","title":"CompetitorSocialReactionsConfig","description":"Config for competitor_social_reactions.\n\nInputs up to MAX_COMPANY_URLS_PER_SIGNAL competitor company URLs. For\neach, we resolve the company, find its BD/Sales/CS/Ops/Founder profiles,\nand surface posts those profiles *engaged with* (liked / commented) but\ndid not author. Each surfaced post becomes one author lead plus its\nother engagers.\n\nPosts from all competitors share the signal's daily_lead_limit and are\nprocessed in round-robin order (one post per competitor in turn) so\nno single URL monopolizes the budget.\n\nFor a poster who has gone quiet rather than one who is actively engaging,\nsee `dormant_linkedin_poster` — a separate signal type."},"CustomWebhookDestination":{"properties":{"url":{"type":"string","title":"Url","description":"HTTPS endpoint that receives each lead (same payload as webhookUrl)."}},"type":"object","required":["url"],"title":"CustomWebhookDestination","examples":[{"url":"https://yourapp.com/hooks/rodz"}]},"DepartmentGrowthConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Countries / regions to target (e.g. France)"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company sizes to include (51-200, 201-500, ...)"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Industries to target. Use industry names from GET /api/v1/signals/industries — the entries with `kind: \"industry\"`, e.g. 'Software Development'. Unlike the other signals, this one resolves each name to a LinkedIn industry id, so a `kind: \"category\"` name does NOT expand to the industries inside it: 9 of the 19 categories resolve to nothing at all and are dropped, and the other 10 narrow to the single same-named industry. A name that does not resolve is skipped silently, so copy values verbatim. Empty = all industries."},"growthMin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Growthmin","description":"Signed headcount-growth floor % (negative = shrinking)"},"growthMax":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Growthmax","description":"Signed headcount-growth ceiling %"},"department":{"anyOf":[{"type":"string","enum":["Accounting","Administrative","Arts and Design","Business Development","Community and Social Services","Consulting","Education","Engineering","Entrepreneurship","Finance","Healthcare Services","Human Resources","Information Technology","Legal","Marketing","Media and Communication","Military and Protective Services","Operations","Product Management","Program and Project Management","Purchasing","Quality Assurance","Real Estate","Research","Sales","Support"]},{"type":"null"}],"title":"Department","description":"Department whose headcount to track. Must be one of the supported departments (see allowed values)."}},"additionalProperties":true,"type":"object","title":"DepartmentGrowthConfig","description":"company_growth scoped to a specific department (Sales, Engineering, ...)."},"DormantLinkedInPosterConfig":{"properties":{"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"jobTitles":{"items":{"type":"string"},"type":"array","title":"Jobtitles","description":"Job titles to target (e.g. \"Founder\", \"Dirigeant\", \"Marketing Director\"). Defines who the signal looks for. Titles to exclude use the inherited excluded_titles."},"reactivationGapDays":{"type":"integer","title":"Reactivationgapdays","description":"Minimum silence (in days) before a fresh post counts as a reactivation. 75 ≈ ~2.5 months.","default":75},"dailyExtractLimit":{"type":"integer","title":"Dailyextractlimit","description":"Max profiles to extract per day on recurring runs.","default":100}},"type":"object","title":"DormantLinkedInPosterConfig","description":"Config for dormant_linkedin_poster.\n\nThe signal builds a Sales Navigator people-search from the user's ICP /\npersona filters and ALWAYS pins LinkedIn's native \"Posted on LinkedIn\"\n(POSTED_ON_LINKEDIN) facet — so the extracted pool is people in the ICP who\nposted recently. Each extracted profile is then checked for a dormant\nreactivation (first original post after a long silence); only reactivated\nprofiles become leads.\n\nInherits the ICP filters from CommonFilterConfig (company_size_filters,\nlocations, industry_filters, target_personas, custom_persona_titles,\nexcluded_*) and enrichment toggles from EnrichmentConfig (get_emails,\nget_phones).","examples":[{"company_size_filters":["11-50","51-200"],"get_emails":true,"job_titles":["Founder","Dirigeant","Gérant","CEO"],"locations":["France"],"reactivation_gap_days":75}]},"EmeliaDestination":{"properties":{"campaignId":{"type":"string","title":"Campaignid","description":"Emelia campaign id."},"campaignType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Campaigntype","description":"Emelia campaign type (\"email\" or \"linkedin\")."}},"type":"object","required":["campaignId"],"title":"EmeliaDestination","examples":[{"campaignId":"6501a2b3c4d5e6f7","campaignType":"email"}]},"EmployeeDepartureConfig":{"properties":{"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size bands to keep, judged on the NEW employer. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company passes when its declared size band OR its employee count falls in one of these bands; a count within 10% of a band edge counts for both bands (48 employees passes \"51-200\"). A company declaring a band of 501 or more employees is never placed in a smaller band by a low count. A company whose size cannot be determined is delivered only when this selection includes a band under 51 employees. Empty = every size."},"jobTitles":{"items":{"type":"string"},"type":"array","title":"Jobtitles","description":"Preset personas whose DEPARTURE is watched. Same values as `targetPersonas` (e.g. \"CTO\", \"Product Director\")."},"customTitles":{"items":{"type":"string"},"type":"array","title":"Customtitles","description":"Additional custom titles whose departure is watched."},"locationFilter":{"type":"string","title":"Locationfilter","description":"Not used by this signal - accepted for compatibility only and filters nothing. Put the places you want in `locations`.","default":"","deprecated":true},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations of the FORMER company (e.g. ['France', 'Paris'])."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Former-company locations to exclude from results."},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company size bands to drop, judged strictly on the declared band or on the employee count - the 10% tolerance does not widen an exclusion. Same nine values as `companySizeFilters`."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Titles to keep out. A case-insensitive substring check on the current title (\"manager\" removes every title containing that word), applied before the inclusion lists - use it to remove a level the \"or above\" rule would otherwise admit."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"maxJobAgeDays":{"type":"integer","title":"Maxjobagedays","description":"Not used by this signal - accepted for compatibility with Job Changes configs only.","default":180,"deprecated":true},"publishedDate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publisheddate","description":"Deprecated and ignored — kept only so existing integrations keep validating. Job recency for this signal is controlled entirely by `maxJobAgeDays`, and every job change we deliver started within the last 180 days at minimum. Setting this has no effect on which leads you receive.","deprecated":true},"deliverPersonas":{"items":{"type":"string"},"type":"array","title":"Deliverpersonas","description":"Persona display names to reach at the company the employee left (e.g. 'VP Sales')."},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per former company. \"top_ranked\" (default) delivers only the best-ranked contact; \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps either mode.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum leads to create per former company. Set to 1 for strictly one per company."}},"type":"object","title":"EmployeeDepartureConfig","description":"Config for employee_departure.\n\nInherits JobChangesConfig watch filters:\n- job_titles / custom_titles = which DEPARTING roles to watch\n- company_size_filters / industry_filters / locations / excluded_* =\n  ICP filters applied to the FORMER company\nAdds deliver_personas = the persona(s) to reach at the company the\nemployee left."},"EnabledDestination":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"Turn this destination on or off for the signal."}},"type":"object","required":["enabled"],"title":"EnabledDestination","examples":[{"enabled":true}]},"EnrichmentResponse":{"properties":{"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data","description":"Enrichment result, or null if no data found"},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Unique request identifier"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Present only when `data` is null, to explain why nothing was returned. `not_found` — the company/contact could not be matched. `domain_linkedin_mismatch` — a company was located but the registered website on its LinkedIn page does not match the `domain` you requested, so it was not returned to avoid handing back the wrong company (verify the domain, or query by `companyName` / `companyLinkedinUrl` instead)."}},"type":"object","title":"EnrichmentResponse","description":"Standard response wrapper for all enrichment endpoints."},"EventAttendeesConfig":{"properties":{"postedLimit":{"type":"string","title":"Postedlimit","description":"Time window: \"24h\", \"week\", \"month\"","default":"24h"},"minEngagement":{"type":"integer","title":"Minengagement","description":"Minimum engagement count","default":5},"maxPosts":{"type":"integer","title":"Maxposts","description":"Max posts to process (0 = unlimited)","default":0},"engagementTypes":{"items":{"type":"string","enum":["likes","comments","poster","both"]},"type":"array","title":"Engagementtypes","description":"Which people on each surfaced post become leads. Combine the values in this array:\n- \"likes\": people who reacted to the post.\n- \"comments\": people who commented on the post.\n- \"poster\": the post author. Use [\"poster\"] alone for an author-only signal (no engager fan-out — typically much less noise).\n- \"both\": intersection of likes AND comments (highest intent, smallest volume).\nExamples: [\"likes\", \"comments\"] = union (reacted OR commented); [\"poster\"] = author only; [\"poster\", \"comments\"] = author + commenters.","default":["likes","comments"]},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"eventUrls":{"items":{"type":"string"},"type":"array","title":"Eventurls","description":"LinkedIn event URLs whose attendees to track (e.g. https://www.linkedin.com/events/<slug><id>/). Required for activation."}},"type":"object","title":"EventAttendeesConfig","description":"Configuration for an Event Attendees signal.\n\nGiven one or more LinkedIn event URLs, the people attending each event are\nsurfaced and turned into leads, filtered by your ICP filters (persona /\ncompany size / location / industry) and enrichment toggles."},"ForecastConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target company HQ locations (e.g. ['United States', 'Paris'])"},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Filter by LinkedIn industry category (e.g. 'Software Development'). Mapped to our forecast industry categories before matching."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\""},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude"},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"}},"type":"object","title":"ForecastConfig","description":"Config for the four forward-looking company signals.\n\nShared by forecasted_funding / _ipo / _acquisition / _growth: they differ\nonly in which forecast the mirror is queried on, which is fixed by the\nsignal type, not by config. There is deliberately no forecast-strength\nfield — only the strongest tier is ever served (see forecast_tiers.py).\n\nRegistering this in SIGNAL_CONFIG_MODELS is what gives these signals the\nsame camelCase-to-snake_case normalization every other signal gets. Without\nit a camelCase API caller's ``companySizeFilters`` was stored verbatim and\nthe collector — which reads snake_case — saw no filter at all and returned\nthe unfiltered population.\n\nEvery key the collector reads MUST have a field here. The base models set\n``extra=\"ignore\"``, so a key missing from this model is not passed through:\nit is silently DROPPED on the way to storage."},"ForecastWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to never deliver, even if watched"}},"type":"object","title":"ForecastWatchlistConfig","description":"Config for the four forecasted_*_watchlist types.\n\nNo strength setting, exactly as on the open forecast signals: only the\nstrongest tier is ever delivered, so a lead arriving IS the signal.","examples":[{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"targetPersonas":["Head of Sales"]}]},"FundraisingConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"investmentTypes":{"items":{"type":"string"},"type":"array","title":"Investmenttypes","description":"Funding round types. Valid values: \"pre_seed\", \"seed\", \"series_a\", \"series_b\", \"series_c\", \"series_d\", \"series_e\", \"series_f\", \"series_g\", \"series_h\", \"series_i\", \"series_j\", \"angel\", \"private_equity\", \"debt_financing\", \"convertible_note\", \"grant\", \"corporate_round\", \"equity_crowdfunding\", \"product_crowdfunding\", \"secondary_market\", \"post_ipo_equity\", \"post_ipo_debt\", \"post_ipo_secondary\", \"non_equity_assistance\", \"ico\", \"funding_round\", \"government_subsidy\", \"unknown\""},"amountMin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Amountmin","description":"Minimum funding amount in USD"},"amountMax":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Amountmax","description":"Maximum funding amount in USD"},"announcedPeriod":{"type":"string","title":"Announcedperiod","description":"How recent: \"24h\", \"7d\", \"30d\", \"60d\", \"90d\", \"12m\", \"custom\"","default":"30d"},"hqLocations":{"items":{"type":"string"},"type":"array","title":"Hqlocations","description":"Filter on the funded company's HEADQUARTERS location (e.g. ['France']). Fundraising and M&A are the only signals that filter on headquarters; elsewhere `locations` targets the person or the job."},"excludedHqLocations":{"items":{"type":"string"},"type":"array","title":"Excludedhqlocations","description":"HQ locations to exclude"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Filter by industry (e.g. 'SaaS', 'FinTech', 'HealthTech')"},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"Industries to exclude"},"employeeRange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Employeerange","description":"Deprecated, use companySizeFilters instead"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude"},"investorInclude":{"items":{"type":"string"},"type":"array","title":"Investorinclude","description":"Only keep deals where at least one investor matches (keyword + AI fallback)"},"investorExclude":{"items":{"type":"string"},"type":"array","title":"Investorexclude","description":"Skip deals where any investor matches (keyword + AI fallback)"}},"type":"object","title":"FundraisingConfig","description":"Config for fundraising."},"FundraisingCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/FundraisingConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"FundraisingCreate","description":"Create a Fundraising signal.","examples":[{"config":{"amountMax":50000000,"amountMin":1000000,"announcedPeriod":"30d","companySizeFilters":["11-50","51-200"],"customPersonaTitles":["Chief Growth Officer"],"detectTechnologies":false,"enablePersonaTargeting":true,"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"hqLocations":["France","Germany"],"industryFilters":["Software Development","Financial Services"],"investmentTypes":["seed","series_a","series_b"],"investorExclude":[],"investorInclude":["Sequoia","a16z"],"personaExportMode":"top_ranked","personaLocations":["France"],"targetPersonas":["CEO","Finance Director"]},"dailyLeadLimit":50,"name":"Series A+ in France","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"FundraisingWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"investmentTypes":{"items":{"type":"string"},"type":"array","title":"Investmenttypes","description":"Round types to keep, e.g. `seed`, `series_a`, `private_equity`. Empty = every round type."},"amountMin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amountmin","description":"Minimum funding amount in USD"},"amountMax":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Amountmax","description":"Maximum funding amount in USD"},"announcedPeriod":{"type":"string","title":"Announcedperiod","description":"How far back to look: 24h, 7d, 30d, 60d, 90d, 12m","default":"30d"},"investorInclude":{"items":{"type":"string"},"type":"array","title":"Investorinclude","description":"Only deliver rounds with at least one of these investors"},"investorExclude":{"items":{"type":"string"},"type":"array","title":"Investorexclude","description":"Drop rounds with any of these investors"}},"type":"object","title":"FundraisingWatchlistConfig","description":"Config for fundraising_watchlist.","examples":[{"amountMin":1000000,"announcedPeriod":"30d","companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"investmentTypes":["series_a","series_b"],"targetPersonas":["Head of Sales"]}]},"GmbListingConfig":{"properties":{"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"country":{"type":"string","title":"Country","description":"ISO 2-letter country code. 53 countries are available — the largest are US, FR, DE, AU, GB, IT and ES.","default":"FR"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"Google Maps macro category (e.g. 'Restaurant'). Required if country alone isn't enough to scope the search. Accepts the category name in any of the 43 languages Google Maps supports — 'Restauration', 'Gastronomie' and 'Restaurant' all resolve to the same category, so write it in whichever language you think in."},"subcategory":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subcategory","description":"Google Maps subcategory (e.g. 'Italian restaurant'). Same multi-language handling as `category`."},"cities":{"items":{"type":"string"},"type":"array","title":"Cities","description":"City names (e.g. ['Paris', 'Lyon'])."},"postalCodes":{"items":{"type":"string"},"type":"array","title":"Postalcodes","description":"Postal codes in the selected country (e.g. ['75001', '69001'])."},"minRating":{"anyOf":[{"type":"number","maximum":5.0,"minimum":0.0},{"type":"null"}],"title":"Minrating","description":"Minimum Google rating."},"maxRating":{"anyOf":[{"type":"number","maximum":5.0,"minimum":0.0},{"type":"null"}],"title":"Maxrating","description":"Maximum Google rating."},"minReviews":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Minreviews","description":"Minimum Google review count."},"maxReviews":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Maxreviews","description":"Maximum Google review count."},"hasEmail":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasemail","description":"Only return businesses that have a public email address."},"hasWebsite":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Haswebsite","description":"Only return businesses that have a website."},"hasPhone":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasphone","description":"Only return businesses that have a phone number."},"hasSiret":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hassiret","description":"Only return businesses that have a French SIRET identifier."},"hasFacebook":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasfacebook","description":"Only return businesses with a Facebook page."},"hasInstagram":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasinstagram","description":"Only return businesses with an Instagram account."},"hasLinkedin":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Haslinkedin","description":"Only return businesses with a LinkedIn page."},"hasYoutube":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasyoutube","description":"Only return businesses with a YouTube channel."},"hasTwitter":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hastwitter","description":"Only return businesses with an X (Twitter) account."},"hasTiktok":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hastiktok","description":"Only return businesses with a TikTok account."},"hasClaimed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Hasclaimed","description":"Filter on whether the owner has claimed their Google Business listing. Set it to `false` for the more useful half: an unclaimed listing means nobody is managing that presence yet, which is a different conversation from selling to a business that already runs its own page. Claimed status is not known for every country we cover — where it is missing, this filter matches nothing, so leave it unset rather than narrowing a search that would otherwise return results."},"apeCodes":{"items":{"type":"string"},"type":"array","title":"Apecodes","description":"French APE/NAF codes to filter on."},"keepOnlyConfirmedNew":{"type":"boolean","title":"Keeponlyconfirmednew","description":"Premium filter. When true, every candidate is cross-checked against the SIRENE registry; businesses registered more than 6 months ago are dropped as false positives. Auto-entrepreneurs and businesses not present in SIRENE are kept. Switches per-lead pricing from 1 to 5 credits.","default":false},"confirmedNewThresholdDays":{"anyOf":[{"type":"integer","maximum":730.0,"minimum":30.0},{"type":"null"}],"title":"Confirmednewthresholddays","description":"Custom SIRENE freshness cutoff (in days) for keep_only_confirmed_new. Defaults to 180 when null. Lower it (e.g. 90) for verticals like food trucks where genuinely new openings dominate; raise it (e.g. 365) for longer-tail trades where SIRENE registration lags real opening. Only consulted when keep_only_confirmed_new is true."},"keepOnlyNewlyListed":{"type":"boolean","title":"Keeponlynewlylisted","description":"Only deliver businesses that appeared on Google Maps recently, rather than every business matching your filters. Available in every country. Leave it off to receive all matching businesses we find; turn it on to receive only the newly listed ones.","default":false},"newlyListedThresholdDays":{"anyOf":[{"type":"integer","maximum":730.0,"minimum":1.0},{"type":"null"}],"title":"Newlylistedthresholddays","description":"How recently a business must have appeared on Google Maps to count as newly listed. Defaults to 180 when null. Only consulted when keepOnlyNewlyListed is true."}},"type":"object","title":"GmbListingConfig","description":"Config for gmb_listing (GMB Discovery — newly indexed Google Maps businesses).\n\nMulti-country, but the optional ``keep_only_confirmed_new`` freshness filter\nrelies on the French SIRENE registry, so it's only available for FR. Other\ncountries serve from the mirror without the SIRENE cross-check."},"GongDestination":{"properties":{"flowId":{"type":"string","title":"Flowid","description":"Sales-engagement flow id to assign leads to."},"ownerEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owneremail","description":"Flow owner email."},"integrationId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Integrationid"}},"type":"object","required":["flowId"],"title":"GongDestination","examples":[{"flowId":"7890123","ownerEmail":"rep@acme.com"}]},"GoogleSheetsDestination":{"properties":{"sheetUrl":{"type":"string","title":"Sheeturl","description":"Target Google Sheet URL (must be accessible to your connected Google account)."}},"type":"object","required":["sheetUrl"],"title":"GoogleSheetsDestination","examples":[{"sheetUrl":"https://docs.google.com/spreadsheets/d/1AbCdEf/edit"}]},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError","example":{"detail":[{"loc":["query","post"],"msg":"Field required","type":"missing"}]}},"InstantlyDestination":{"properties":{"campaignId":{"type":"string","title":"Campaignid","description":"Instantly campaign id to push leads into."}},"type":"object","required":["campaignId"],"title":"InstantlyDestination","examples":[{"campaignId":"01920e5f-3c7a-7b1e-9d2f-8a1b2c3d4e5f"}]},"JobChangeWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"profiles":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedProfileSeed"}]},"type":"array","title":"Profiles","description":"The people to watch. Each entry is either a LinkedIn profile URL on its own (`\"https://www.linkedin.com/in/marie-dupont\"`), or an object `{url, currentTitle, currentCompany, currentCompanyUrl}` carrying the role you already have on file. Both forms can be mixed.\n\nSend the role when you have it. Every check is billed, the first one included. With a role on file, the first check compares against it and reports any change straight away. With a bare URL, the first check can only report a move made in the last 6 months (it compares the current job with the one before it); anyone who moved earlier stays invisible, recorded as they stand today, and a later move is reported at the next check, one `cadenceHours` later.\n\nCountry subdomains and tracking query strings are accepted and normalized; anything that is not a personal profile URL is rejected and reported in `profilesRejected`."},"detectionMode":{"type":"string","enum":["title","company","both"],"title":"Detectionmode","description":"What counts as a change. `company` (default) fires only when the person moves employer — the highest-intent event. `title` fires on an internal promotion or role change at the same employer. `both` fires on either.","default":"company"},"cadenceHours":{"type":"integer","enum":[0,24,168,360,720,1080,1440,2160],"title":"Cadencehours","description":"How often each watched person is re-checked, in hours. 168 (weekly) is the default. `0` means check the list once and never again.","default":168}},"type":"object","title":"JobChangeWatchlistConfig","description":"Config for job_change_watchlist — the PUBLIC API shape.\n\nCompany sibling of ``JobOffersWatchlistConfig``: that one watches a list of\nCOMPANIES for new postings, this one watches a list of PEOPLE for job\nchanges. The in-app signal takes its people from a CSV upload or a CRM list,\nneither of which REST can express, so the API accepts them inline as\n`profiles`. Everything else mirrors WatchlistJobChangeConfig\n(app/schemas/watchlist_configs.py); the create endpoint writes the list into\nwatchlist_profile and stores the rest on the signal.","examples":[{"cadenceHours":168,"detectionMode":"company","getEmails":true,"profiles":["https://www.linkedin.com/in/marie-dupont","https://www.linkedin.com/in/jean-martin"]}]},"JobChangesConfig":{"properties":{"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size bands to keep, judged on the NEW employer. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company passes when its declared size band OR its employee count falls in one of these bands; a count within 10% of a band edge counts for both bands (48 employees passes \"51-200\"). A company declaring a band of 501 or more employees is never placed in a smaller band by a low count. A company whose size cannot be determined is delivered only when this selection includes a band under 51 employees. Empty = every size."},"jobTitles":{"items":{"type":"string"},"type":"array","title":"Jobtitles","description":"Preset personas to track - the `name` values from GET /api/v1/personas (e.g. \"CTO\", \"Sales Director\"). A preset is a function plus a seniority level, matched by MEANING in any language, not as text: a person qualifies when their current role is in that function at that level OR ABOVE. A Director-level preset accepts VPs and heads of the function and refuses a plain Manager; a Manager-level preset also accepts Directors. `jobTitles` and `customTitles` form ONE list - matching any single entry is enough."},"customTitles":{"items":{"type":"string"},"type":"array","title":"Customtitles","description":"Your own titles, added to `jobTitles` (the two lists are a union, not an intersection). A custom title is matched by meaning like a preset and carries the seniority its own words state: \"Marketing Director\" is Director-level and accepts that level or above; a title with no level word (\"Growth Marketing\") accepts every professional level. A broad custom title therefore WIDENS the signal - it never narrows the presets. Keep a level out with `excludedTitles`."},"locationFilter":{"type":"string","title":"Locationfilter","description":"Not used by this signal - accepted for compatibility only and filters nothing. Put the places you want in `locations`.","default":"","deprecated":true},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Places the PERSON must be in - judged on their profile location, not on the company's headquarters (e.g. ['France', 'Lyon']). One matching entry is enough. A profile with no location is dropped when this is set. A profile that states only a country does not match a city or region entry: add the country itself if you want those people. Names are validated on write (400 INVALID_LOCATION); check ambiguous ones with GET /api/v1/enrichment/validate-location first."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Places to drop, judged on the person's profile location. With no `locations`, a profile without a location is kept."},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company size bands to drop, judged strictly on the declared band or on the employee count - the 10% tolerance does not widen an exclusion. Same nine values as `companySizeFilters`."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Titles to keep out. A case-insensitive substring check on the current title (\"manager\" removes every title containing that word), applied before the inclusion lists - use it to remove a level the \"or above\" rule would otherwise admit."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"maxJobAgeDays":{"type":"integer","title":"Maxjobagedays","description":"How recent the new position must be, in days from its start date. Minimum and default 180: a smaller value - 0 included - is accepted and applied as 180 (the response's `applied` field shows the value in force). Positions are detected within about a year of the change, so values above 365 add nothing.","default":180},"publishedDate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Publisheddate","description":"Deprecated and ignored — kept only so existing integrations keep validating. Job recency for this signal is controlled entirely by `maxJobAgeDays`, and every job change we deliver started within the last 180 days at minimum. Setting this has no effect on which leads you receive.","deprecated":true}},"type":"object","title":"JobChangesConfig","description":"Config for job_changes."},"JobChangesCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/JobChangesConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"JobChangesCreate","description":"Create a Job Changes signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500","501-1000"],"customTitles":["Head of Platform"],"detectTechnologies":false,"excludedCompanySizeFilters":["Self-employed","1-10"],"excludedLocations":[],"excludedTitles":[],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"jobTitles":["CTO","Product Director"],"locations":["France"]},"dailyLeadLimit":50,"name":"Decision makers changing jobs","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"JobOffersConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"jobTitleInclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleinclude","description":"Keywords the job title must include. Each keyword is matched anywhere in the title, not against the whole title: `sales` matches \"Head of Sales EMEA\". A multi-word keyword must appear with its words in that order (`head of sales` does not match \"Head of Inside Sales\"). Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobTitleIncludeAll`."},"jobTitleExclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleexclude","description":"Keywords the job title must not include: a job is skipped when its title contains any of them anywhere (`intern` skips \"Sales Intern\"). Case and accents are ignored."},"jobTitleIncludeAll":{"type":"boolean","title":"Jobtitleincludeall","description":"Require EVERY `jobTitleInclude` keyword in the title instead of any one.","default":false},"jobDescriptionInclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptioninclude","description":"Keywords the job description must include, each matched anywhere in the description text (`Salesforce` matches a posting asking for \"experience with Salesforce CRM\"). A multi-word keyword must appear with its words in that order. Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobDescriptionIncludeAll`."},"jobDescriptionExclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptionexclude","description":"Keywords the job description must not include: a job is skipped when its description contains any of them anywhere. Case and accents are ignored."},"jobDescriptionIncludeAll":{"type":"boolean","title":"Jobdescriptionincludeall","description":"Require EVERY `jobDescriptionInclude` keyword in the description instead of any one.","default":false},"jobTitleQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitlequery","description":"Advanced: a boolean search string applied to the job title instead of `job_title_include` / `job_title_exclude` (operators: AND, OR, NOT, parentheses, quoted phrases — e.g. `(\"head of marketing\" OR \"VP marketing\") AND NOT intern`). When non-empty, the include/exclude title lists are ignored. Leave null for the simple list-based mode."},"jobDescriptionQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescriptionquery","description":"Advanced: a boolean search string applied to the job description instead of `job_description_include` / `job_description_exclude` (same operator syntax as `job_title_query`). When non-empty, the include/exclude description lists are ignored. Leave null for simple list-based mode."},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Job locations to search, e.g. `[\"France\", \"Belgium\"]`. Applies to the JOB's location, not the hiring company's headquarters: a job in France at a company headquartered abroad matches France. Optional — **leave it empty or omit it to search worldwide**. Multiple locations are OR'd, so adding more widens the search rather than narrowing it. Pass names, not ids (`\"France\"`); unrecognised names are rejected with 400 `INVALID_LOCATION`. A worldwide signal can match far more jobs than a country-scoped one, so set `dailyLeadLimit` to what you actually want delivered. On job signals `dailyLeadLimit` counts companies: each company is delivered at most once a day, however many jobs it posts."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Job locations to exclude from results"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return jobs at companies in these industries. Uses LinkedIn industry names, the same vocabulary as every other signal (e.g. 'Software Development', 'Hospitality', 'Staffing and Recruiting'). Empty = all industries. Call GET /api/v1/signals/industries for the valid list; names must match exactly."},"companyIndustryExcluded":{"items":{"type":"string"},"type":"array","title":"Companyindustryexcluded","description":"Exclude companies in these industries — typically agencies and consultancies posting on a client's behalf. Same LinkedIn industry vocabulary as `industryFilters`. To exclude named companies rather than whole industries, use `excludedWebsites`. Defaults to recruitment agencies and consultancies.","default":["Staffing and Recruiting","Business Consulting and Services"]},"excludedWebsites":{"items":{"type":"string"},"type":"array","title":"Excludedwebsites","description":"Company website domains to exclude from results — e.g. companies you already work with. Accepts domains or URLs (normalized to the bare domain, like 'acme.com'); matching is case-insensitive and ignores 'www.'."},"publishedDate":{"type":"string","title":"Publisheddate","description":"How far back the signal's FIRST run looks for job offers, and the oldest a delivered offer may be. After the first run the signal follows offers published in the last 7 days, so a longer value adds history once, at the start. Use \"24h\", or a count followed by a unit — \"7d\" / \"30d\" (days), \"2w\" (weeks), \"3m\" / \"12m\" (months). The spelled-out forms (\"7 days\", \"3 months\") are accepted too. Defaults to \"7d\"; an unrecognised value falls back to 7 days.","default":"7d"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"companyOnlyWhenContactsRefused":{"type":"boolean","title":"Companyonlywhencontactsrefused","description":"Deliver the company alone, with no contact, when people were found at it but every one was filtered out by your persona, location or company size settings. Off by default: that company produces nothing, the same as before this option existed. On: you still get the company — priced and delivered exactly like a company-only lead, the same as when nobody at all is found there. Only applies when `enablePersonaTargeting` is on.","default":false}},"type":"object","title":"JobOffersConfig","description":"Config for job_offers."},"JobOffersCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/JobOffersConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"JobOffersCreate","description":"Create a Job Offers signal.","examples":[{"config":{"companySizeFilters":["51-200","201-500"],"customPersonaTitles":[],"detectTechnologies":false,"enablePersonaTargeting":false,"excludedWebsites":["acme.com"],"getEmails":false,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"jobDescriptionExclude":[],"jobDescriptionInclude":["Python","React"],"jobDescriptionIncludeAll":false,"jobTitleExclude":["Intern"],"jobTitleInclude":["Senior","Lead","Staff"],"jobTitleIncludeAll":false,"locations":["Paris, France","Remote"],"personaExportMode":"top_ranked","personaLocations":[],"publishedDate":"7d","targetPersonas":[]},"dailyLeadLimit":100,"name":"Senior engineer hires in SaaS","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"JobOffersWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","title":"Companies","description":"Companies to watch. Each entry is either a plain string — a name (`\"Doctolib\"`), a domain (`\"doctolib.fr\"`) or a LinkedIn company URL — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company. Both forms can be mixed. Send every identifier you have: the LinkedIn URL identifies the company exactly, and a name alone cannot separate two companies that share one. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed).\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved."},"maxJobsPerCompanyPerDay":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Maxjobspercompanyperday","description":"Most postings turned into leads per company per day. Total volume is roughly this x the number of companies watched.","default":3},"cadenceHours":{"type":"integer","title":"Cadencehours","description":"How often each company is checked, in hours.","default":24},"jobTitleInclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleinclude","description":"Keywords the job title must include. Each keyword is matched anywhere in the title, not against the whole title: `sales` matches \"Head of Sales EMEA\". A posting is kept when its title contains ANY one of them. Case and accents are ignored."},"jobTitleExclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleexclude","description":"Keywords the job title must not include: a posting is skipped when its title contains any of them anywhere (`intern` skips \"Sales Intern\")."},"firstRunLookbackDays":{"type":"integer","maximum":365.0,"minimum":1.0,"title":"Firstrunlookbackdays","description":"How far back the FIRST check of a newly added company looks. Bounds the initial backfill so a company does not deliver its whole history at once.","default":30},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Off = one company-level lead per posting. On = resolve the hiring decision-makers behind each posting as person-leads.","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Cap contacts per company when persona targeting is on."},"companyOnlyWhenContactsRefused":{"type":"boolean","title":"Companyonlywhencontactsrefused","description":"Deliver the company alone, with no contact, when people were found at it but every one was filtered out by your persona, location or company size settings. Off by default: that company produces nothing, the same as before this option existed. On: you still get the company — priced and delivered exactly like a company-only lead, the same as when nobody at all is found there.","default":false}},"type":"object","title":"JobOffersWatchlistConfig","description":"Config for job_offers_watchlist — the PUBLIC API shape.\n\nThe in-app signal takes its companies from a CSV upload, which REST cannot\nexpress, so the API accepts them inline as `companies`. Everything else\nmirrors WatchlistJobOffersConfig (app/schemas/watchlist_configs.py); the\ncreate endpoint writes the list into watchlist_company and stores the rest\non the signal.","examples":[{"cadenceHours":24,"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"companyOnlyWhenContactsRefused":true,"enablePersonaTargeting":true,"firstRunLookbackDays":30,"getEmails":true,"jobTitleInclude":["Account Executive","Sales"],"maxJobsPerCompanyPerDay":3,"maxLeadsPerCompany":2,"targetPersonas":["Head of Sales"]}]},"LemlistDestination":{"properties":{"campaignId":{"type":"string","title":"Campaignid","description":"Lemlist campaign id."},"integrationId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Integrationid","description":"Which connected Lemlist account to use. Required only if you've connected more than one; discover ids via GET /api/v1/integrations."}},"type":"object","required":["campaignId"],"title":"LemlistDestination","examples":[{"campaignId":"cam_aBc123XyZ","integrationId":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}]},"LgmDestination":{"properties":{"audienceName":{"type":"string","title":"Audiencename","description":"LaGrowthMachine audience name."},"integrationId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Integrationid","description":"Which connected account (only if more than one)."}},"type":"object","required":["audienceName"],"title":"LgmDestination","examples":[{"audienceName":"Inbound leads"}]},"LinkedInConnectionsConfig":{"properties":{"restrictToCompanies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","title":"Restricttocompanies","description":"Only deliver leads at these companies. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company; both forms can be mixed. The more identifiers you send, the more of your list is recognised. Matching is exact once punctuation and legal suffixes are ignored. Consumed on create, so it is NOT echoed back in `config`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/companies`.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved."},"restrictToProfiles":{"items":{"type":"string"},"type":"array","title":"Restricttoprofiles","description":"Only deliver leads for these people — LinkedIn profile URLs. Consumed on create like `restrictToCompanies`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/profiles`."},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"linkedinCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Linkedincompanyurls","description":"LinkedIn COMPANY page URLs to monitor — not a personal profile URL (e.g. `\"https://www.linkedin.com/company/acme\"`, not `\".../in/...\"`). We discover employees of these companies and queue connection requests; once accepted, we track their new connections. Either this or `linkedin_profile_urls` is required for activation."},"linkedinProfileUrls":{"items":{"type":"string"},"type":"array","title":"Linkedinprofileurls","description":"LinkedIn profile URLs of specific people whose new connections you want to track (e.g. `\"https://www.linkedin.com/in/marie-dupont\"`). Use when you already know who you want to follow. Each person produces leads only once they have accepted our connection request — that can take days, and someone who never accepts produces none. Editable on a live signal: a `PATCH` that adds URLs starts watching those people, one that removes URLs stops watching them (send the full list you want)."},"searchUrl":{"type":"string","title":"Searchurl","description":"LinkedIn Sales Navigator search URL used for extraction","default":""}},"type":"object","title":"LinkedInConnectionsConfig","description":"Config for Competitor Connections and Competitor Customer Care Connections.\n\nWatches the NEW LinkedIn connections of people at your competitors. Provide\n`linkedinCompanyUrls`, `linkedinProfileUrls`, or both:\n\n- `linkedinCompanyUrls`: we find the relevant team at each company (sales\n  and business teams for Competitor Connections, customer success and\n  support for Customer Care) and watch their new connections.\n- `linkedinProfileUrls`: specific people you already know you want to\n  watch. A named person starts producing leads only once they have\n  accepted our connection request, which can take days, and a person who\n  never accepts produces none.\n\nA `PATCH` that adds URLs to `linkedinProfileUrls` starts watching those\npeople; one that removes URLs stops watching them."},"LocationValidationResponse":{"properties":{"valid":{"type":"boolean","title":"Valid","description":"True if the name is a recognized location."},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Geo id for the recognized location (null when not recognized)."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The geo directory's label for the matched location — use it to confirm your input resolved to the place you meant (e.g. `uk` matches `Ukraine`). Null when not recognized."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Human-readable reason when `valid` is false; null when valid."}},"type":"object","required":["valid"],"title":"LocationValidationResponse","description":"Result of validating a location name for use in a signal's location filter.","examples":[{"id":"101282230","name":"Germany","valid":true}]},"MergersAcquisitionsConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"dealTypes":{"items":{"type":"string"},"type":"array","title":"Dealtypes","description":"Deal types. Valid values: \"acquisition\", \"merger\", \"leveraged_buyout\", \"management_buyout\""},"minAmount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Minamount","description":"Minimum deal amount in USD"},"announcedPeriod":{"type":"string","title":"Announcedperiod","description":"How recent: \"24h\", \"7d\", \"30d\", \"60d\", \"90d\", \"12m\", \"custom\"","default":"30d"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Filter by industry (e.g. 'SaaS', 'Enterprise Software')"},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"Industries to exclude"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude"},"hqLocations":{"items":{"type":"string"},"type":"array","title":"Hqlocations","description":"Filter on the ACQUIRER's headquarters location (e.g. ['France']). Fundraising and M&A are the only signals that filter on headquarters; elsewhere `locations` targets the person or the job."},"excludedHqLocations":{"items":{"type":"string"},"type":"array","title":"Excludedhqlocations","description":"HQ locations to exclude"}},"type":"object","title":"MergersAcquisitionsConfig","description":"Config for mergers_acquisitions."},"MergersAcquisitionsCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/MergersAcquisitionsConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"MergersAcquisitionsCreate","description":"Create a Mergers & Acquisitions signal.","examples":[{"config":{"announcedPeriod":"30d","companySizeFilters":["51-200","201-500"],"customPersonaTitles":["Chief Strategy Officer"],"dealTypes":["acquisition","merger"],"detectTechnologies":false,"enablePersonaTargeting":true,"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"hqLocations":["France","United Kingdom"],"industryFilters":["Software Development","IT Services and IT Consulting"],"minAmount":500000,"personaExportMode":"top_ranked","personaLocations":[],"targetPersonas":["CEO","Finance Director"]},"dailyLeadLimit":50,"name":"SaaS acquisitions in Europe","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"MergersAcquisitionsWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"watchSide":{"type":"string","enum":["acquirer","acquiree","both"],"title":"Watchside","description":"Which side of a deal a watched company must be on. `acquiree` = it got bought (often re-opens a closed account); `acquirer` = it bought someone (budget, and an integration to support); `both` (default) = either. The lead is always the WATCHED company, and the side it played is delivered as `signal.deal_role`.","default":"both"},"dealTypes":{"items":{"type":"string"},"type":"array","title":"Dealtypes","description":"Deal types to keep, e.g. `acquisition`, `merger`. Empty = all deals."},"minAmount":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Minamount","description":"Minimum deal amount in USD"},"announcedPeriod":{"type":"string","title":"Announcedperiod","description":"How far back to look: 24h, 7d, 30d, 60d, 90d, 12m","default":"30d"}},"type":"object","title":"MergersAcquisitionsWatchlistConfig","description":"Config for mergers_acquisitions_watchlist.","examples":[{"announcedPeriod":"30d","companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"}],"dealTypes":["acquisition"],"getEmails":true,"watchSide":"both"}]},"MutualConnectionsConfig":{"properties":{"restrictToCompanies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","title":"Restricttocompanies","description":"Only deliver leads at these companies. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company; both forms can be mixed. The more identifiers you send, the more of your list is recognised. Matching is exact once punctuation and legal suffixes are ignored. Consumed on create, so it is NOT echoed back in `config`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/companies`.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved."},"restrictToProfiles":{"items":{"type":"string"},"type":"array","title":"Restricttoprofiles","description":"Only deliver leads for these people — LinkedIn profile URLs. Consumed on create like `restrictToCompanies`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/profiles`."},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"linkedinProfileUrls":{"items":{"type":"string"},"type":"array","title":"Linkedinprofileurls","description":"The two LinkedIn profile URLs to compare, A and B. Any two people. A profile that hides its connection list on LinkedIn cannot be read; the signal reports it as not visible."},"oneTimeExtractCount":{"type":"integer","maximum":25000.0,"minimum":0.0,"title":"Onetimeextractcount","description":"How many mutual connections to deliver, once — counted in leads delivered after your filters. Not metered by `dailyLeadLimit`; billed per mutual connection delivered. `0` skips this part: no existing mutual connection is delivered or billed.","default":100},"dailyNewConnections":{"type":"boolean","title":"Dailynewconnections","description":"After the one-time extract, keep delivering people who newly become connected to both profiles, up to `dailyLeadLimit` a day. Existing mutual connections beyond `oneTimeExtractCount` are never delivered. `false` stops the signal once the one-time extract is complete.","default":false},"searchUrl":{"type":"string","title":"Searchurl","description":"Operational — set by the system","default":""}},"type":"object","title":"MutualConnectionsConfig","description":"Config for mutual_connections: the people connected to both of two LinkedIn profiles.\n\nName any two LinkedIn profiles, A and B — a prospect and someone on your side,\ntwo decision makers at one account, an investor and a founder; neither has to\nbe you. Each lead is someone connected to both, filtered to the roles and\ncompanies you target.\n\nYour filters (personas, company size, location, industry, exclusions) are\napplied to both networks. How many mutual connections exist is only known\nonce both networks have been read; until then the signal reports how many\npeople of each network have been read\n(`GET /api/v1/signals/{signalId}/mutual-connections`).\n\n- **One-time extract** (`oneTimeExtractCount`): up to that many mutual\n  connections, delivered once, as they are found — not metered by\n  `dailyLeadLimit`.\n- **Daily new mutual connections** (`dailyNewConnections`): afterwards, keep\n  delivering people who newly become connected to both, under\n  `dailyLeadLimit`.\n\nExisting mutual connections are delivered ONLY by the one-time extract, up\nto `oneTimeExtractCount`; with `0`, none is delivered or billed."},"NewDecisionMakerWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"customJobTitles":{"items":{"type":"string"},"type":"array","title":"Customjobtitles","description":"Extra job titles to accept alongside `targetPersonas`, matched as written (e.g. `\"Head of Revenue Operations\"`). Use this for a title your industry uses that the standard personas don't cover."},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Maximum leads delivered per run. Arrivals are bursty — a large list can be quiet for days and then deliver a cluster — so this is what makes spend predictable.","default":25}},"type":"object","title":"NewDecisionMakerWatchlistConfig","description":"Config for new_decision_maker_watchlist — the PUBLIC API shape.\n\nThe inverse of ``JobChangeWatchlistConfig``. That one watches a list of\nPEOPLE and reports when they move; this one watches a list of COMPANIES and\nreports the people arriving into them. The person is the discovery, which is\nwhy no existing signal could answer it: a job-change watchlist can only ever\nreport on people already on the list.","examples":[{"cadenceHours":24,"companies":["https://www.linkedin.com/company/lemlist",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"Doctolib"],"customJobTitles":["Head of Revenue Operations"],"dailyLeadLimit":25,"getEmails":true,"targetPersonas":["Sales Director","CTO"]}]},"PersonConnectionsConfig":{"properties":{"restrictToCompanies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","title":"Restricttocompanies","description":"Only deliver leads at these companies. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company; both forms can be mixed. The more identifiers you send, the more of your list is recognised. Matching is exact once punctuation and legal suffixes are ignored. Consumed on create, so it is NOT echoed back in `config`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/companies`.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved."},"restrictToProfiles":{"items":{"type":"string"},"type":"array","title":"Restricttoprofiles","description":"Only deliver leads for these people — LinkedIn profile URLs. Consumed on create like `restrictToCompanies`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/profiles`."},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"linkedinProfileUrls":{"items":{"type":"string"},"type":"array","title":"Linkedinprofileurls","description":"LinkedIn profile URLs of the people whose connections you want, 1 to 50. A person who hides their connection list on LinkedIn cannot be read; the signal reports them as not visible."},"oneTimeExtractCount":{"type":"integer","maximum":25000.0,"minimum":0.0,"title":"Onetimeextractcount","description":"How many people to deliver, once, from the watched people's existing connections — counted in leads delivered after your filters, across all watched people. If their networks hold fewer matching people, everyone who matches is delivered. Not metered by `dailyLeadLimit`; billed 3 credits per lead delivered. `0` skips this part: no existing connection is delivered or billed.","default":500},"dailyNewConnections":{"type":"boolean","title":"Dailynewconnections","description":"After the one-time extract, keep delivering the people who newly connect with the watched people, up to `dailyLeadLimit` a day, billed 5 credits per lead delivered. Only people who connect after the signal started watching are delivered: existing connections beyond `oneTimeExtractCount` never are. `false` stops the signal once the one-time extract is complete.","default":false},"searchUrl":{"type":"string","title":"Searchurl","description":"Operational — set by the system","default":""}},"type":"object","title":"PersonConnectionsConfig","description":"Config for person_connections: the network of people you name.\n\nTwo parts, independent of each other, and your filters (personas, company\nsize, location, industry, exclusions) apply to both. With no filter at all,\neveryone is delivered.\n\n- **One-time extract** (`oneTimeExtractCount`): up to that many people from\n  the watched people's EXISTING networks, delivered once, as fast as they\n  are read — not metered by `dailyLeadLimit`. The count is of leads\n  delivered, after your filters, across all watched people together.\n  3 credits per lead.\n- **Daily new connections** (`dailyNewConnections`): once the one-time part\n  is complete, keep delivering the people who newly connect with them,\n  under `dailyLeadLimit`. Off, the signal stops after the one-time part.\n  5 credits per lead.\n\nExisting connections are delivered ONLY by the one-time extract, up to\n`oneTimeExtractCount`. The daily part delivers only people who connect with\na watched person after the signal started watching them: with\n`oneTimeExtractCount` 0, nothing from the existing networks is delivered or\nbilled, and the first read only records where each network stands."},"PublicCampaignOption":{"properties":{"id":{"type":"string","title":"Id","description":"Use this as the destination id: `campaignId` for email tools (instantly/lemlist/smartlead/emelia) and `flowId` for Gong."},"name":{"type":"string","title":"Name","description":"Human-readable name."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Provider status, when available."}},"type":"object","required":["id","name"],"title":"PublicCampaignOption","description":"One selectable push target for an integration.","examples":[{"id":"01920e5f-3c7a-7b1e-9d2f-8a1b2c3d4e5f","name":"Q3 outbound","status":"active"}]},"PublicCampaignsResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/PublicCampaignOption"},"type":"array","title":"Items"}},"type":"object","required":["items"],"title":"PublicCampaignsResponse"},"PublicContractAwardConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"keywordsExclude":{"items":{"type":"string"},"type":"array","title":"Keywordsexclude"},"cpvCodes":{"items":{"type":"string"},"type":"array","title":"Cpvcodes"},"minContractValue":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mincontractvalue"},"maxContractValue":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Maxcontractvalue"},"titulaireCategories":{"items":{"type":"string"},"type":"array","title":"Titulairecategories","description":"Company size: PME, ETI, GE"},"titulaireRegions":{"items":{"type":"string"},"type":"array","title":"Titulaireregions"},"titulaireDepartements":{"items":{"type":"string"},"type":"array","title":"Titulairedepartements"},"acheteurRegions":{"items":{"type":"string"},"type":"array","title":"Acheteurregions"},"acheteurDepartements":{"items":{"type":"string"},"type":"array","title":"Acheteurdepartements"}},"type":"object","title":"PublicContractAwardConfig","description":"Config for public_contract_award (DECP contract awards)."},"PublicIntegrationConnect":{"properties":{"apiKey":{"type":"string","minLength":1,"title":"Apikey","description":"The provider API key."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Optional name to tell apart multiple connected accounts of this provider."},"secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secret","description":"Gong only: signing secret."},"baseUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Baseurl","description":"Gong only: API base URL."}},"type":"object","required":["apiKey"],"title":"PublicIntegrationConnect","description":"Connect (or update) an API-key integration.","examples":[{"apiKey":"sk_live_a1b2c3d4e5","label":"Acme — main"}]},"PublicIntegrationStatus":{"properties":{"provider":{"type":"string","title":"Provider","description":"Provider id to use in destinations + connect URLs."},"name":{"type":"string","title":"Name","description":"Human-readable provider name."},"connected":{"type":"boolean","title":"Connected","description":"Whether this provider is connected on your account."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Account label, if set."},"connectVia":{"type":"string","title":"Connectvia","description":"How to connect: \"api\" (key) or \"dashboard\" (OAuth)."},"updatedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updatedat"}},"type":"object","required":["provider","name","connected","connectVia"],"title":"PublicIntegrationStatus","description":"Connection status for one integration provider (never includes the key).","examples":[{"connectVia":"api","connected":true,"label":"Acme — main","name":"Instantly","provider":"instantly","updatedAt":"2026-07-15T10:00:00+00:00"}]},"PublicIntegrationsResponse":{"properties":{"integrations":{"items":{"$ref":"#/components/schemas/PublicIntegrationStatus"},"type":"array","title":"Integrations"}},"type":"object","required":["integrations"],"title":"PublicIntegrationsResponse"},"PublicTendersConfig":{"properties":{"restrictToCompanies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","title":"Restricttocompanies","description":"Only deliver leads at these companies. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) carrying everything you know about the company; both forms can be mixed. The more identifiers you send, the more of your list is recognised. Matching is exact once punctuation and legal suffixes are ignored. Consumed on create, so it is NOT echoed back in `config`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/companies`.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved."},"restrictToProfiles":{"items":{"type":"string"},"type":"array","title":"Restricttoprofiles","description":"Only deliver leads for these people — LinkedIn profile URLs. Consumed on create like `restrictToCompanies`; read and edit it at `GET|POST|DELETE /api/v1/watchlists/{signalId}/profiles`."},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"sources":{"items":{"type":"string"},"type":"array","title":"Sources","description":"Data sources. Values: \"boamp\" (French), \"ted\" (European). Default: [\"boamp\"]"},"noticeTypes":{"items":{"type":"string"},"type":"array","title":"Noticetypes","description":"BOAMP notice types. Values: \"APPEL_OFFRE\", \"MAPA\", \"AVIS_DE_CONCESSION\""},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords","description":"Keywords to match in tender subject (objet du marché)"},"keywordsExclude":{"items":{"type":"string"},"type":"array","title":"Keywordsexclude","description":"Keywords to exclude from tender subject"},"marketTypes":{"items":{"type":"string"},"type":"array","title":"Markettypes","description":"Market types to filter (BOAMP). Values: \"Services\", \"Fournitures\", \"Travaux\""},"categoryDescriptors":{"items":{"type":"string"},"type":"array","title":"Categorydescriptors","description":"Category descriptors (BOAMP descripteur_libelle) to filter"},"departmentCodes":{"items":{"type":"string"},"type":"array","title":"Departmentcodes","description":"French department codes to filter (e.g. \"75\", \"69\", \"13\")"},"familleFilter":{"items":{"type":"string"},"type":"array","title":"Famillefilter","description":"Tender families (BOAMP). Values: \"Avis de marché\", \"MAPA\", \"Avis de concession\""},"minDaysUntilDeadline":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Mindaysuntildeadline","description":"Minimum days until response deadline (filters out tenders closing too soon)"},"countryCodes":{"items":{"type":"string"},"type":"array","title":"Countrycodes","description":"ISO 2-letter country codes for TED (e.g. \"FR\", \"DE\", \"IT\")"},"cpvCodes":{"items":{"type":"string"},"type":"array","title":"Cpvcodes","description":"CPV codes for TED filtering (e.g. \"72000000\" = IT services)"},"tedNoticeTypes":{"items":{"type":"string"},"type":"array","title":"Tednoticetypes","description":"TED notice types. Values: \"cn-standard\", \"cn-social\", \"cn-desg\""}},"type":"object","title":"PublicTendersConfig","description":"Config for public_tenders (Public Tenders — BOAMP + TED)."},"PublicTendersWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"sources":{"items":{"type":"string"},"type":"array","title":"Sources","description":"Data sources. Values: \"boamp\" (French), \"ted\" (European). Default: [\"boamp\"]"},"noticeTypes":{"items":{"type":"string"},"type":"array","title":"Noticetypes","description":"BOAMP notice types. Values: \"APPEL_OFFRE\", \"MAPA\", \"AVIS_DE_CONCESSION\""},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords","description":"Keywords to match in tender subject (objet du marché)"},"keywordsExclude":{"items":{"type":"string"},"type":"array","title":"Keywordsexclude","description":"Keywords to exclude from tender subject"},"marketTypes":{"items":{"type":"string"},"type":"array","title":"Markettypes","description":"Market types to filter (BOAMP). Values: \"Services\", \"Fournitures\", \"Travaux\""},"categoryDescriptors":{"items":{"type":"string"},"type":"array","title":"Categorydescriptors","description":"Category descriptors (BOAMP descripteur_libelle) to filter"},"departmentCodes":{"items":{"type":"string"},"type":"array","title":"Departmentcodes","description":"French department codes to filter (e.g. \"75\", \"69\", \"13\")"},"familleFilter":{"items":{"type":"string"},"type":"array","title":"Famillefilter","description":"Tender families (BOAMP). Values: \"Avis de marché\", \"MAPA\", \"Avis de concession\""},"minDaysUntilDeadline":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Mindaysuntildeadline","description":"Minimum days until response deadline (filters out tenders closing too soon)"},"countryCodes":{"items":{"type":"string"},"type":"array","title":"Countrycodes","description":"ISO 2-letter country codes for TED (e.g. \"FR\", \"DE\", \"IT\")"},"cpvCodes":{"items":{"type":"string"},"type":"array","title":"Cpvcodes","description":"CPV codes for TED filtering (e.g. \"72000000\" = IT services)"},"tedNoticeTypes":{"items":{"type":"string"},"type":"array","title":"Tednoticetypes","description":"TED notice types. Values: \"cn-standard\", \"cn-social\", \"cn-desg\""}},"type":"object","title":"PublicTendersWatchlistConfig","description":"Watch a list of public buyers and get told when one publishes a tender.\n\nSame notice filters as the Public Tenders signal — keywords, exclusions,\nnotice types, market types, sources — applied to buyers you name in\n``companies`` instead of to the open feed.\n\n``departmentCodes`` and ``countryCodes`` are accepted but have no effect\nhere, for the reason the market watchlists drop their company filters: they\nask \"is this the KIND of buyer I want?\", which you answered by naming the\nbuyer. Re-applying them could only subtract from a list built by hand, and\nwould subtract on OUR data — a buyer whose department we failed to parse\nwould quietly stop producing leads with nothing in the UI to explain it.\n\n⚠ Buyers are matched on two EXACT keys, never fuzzily: a resolved SIREN\nwhere one is known, the folded name otherwise. Coverage is partial by\ndesign — see the signal description.","examples":[{"companies":["Toulouse Métropole",{"domain":"chu-bordeaux.fr","name":"CHU de Bordeaux"},"Ville de Quimper"],"getEmails":true,"keywords":["logiciel","CRM","prospection commerciale"],"minDaysUntilDeadline":7,"sources":["boamp","ted"]}]},"RecruitmentCampaignConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"jobTitleInclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleinclude","description":"Keywords the job title must include. Each keyword is matched anywhere in the title, not against the whole title: `sales` matches \"Head of Sales EMEA\". A multi-word keyword must appear with its words in that order (`head of sales` does not match \"Head of Inside Sales\"). Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobTitleIncludeAll`."},"jobTitleExclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleexclude","description":"Keywords the job title must not include: a job is skipped when its title contains any of them anywhere (`intern` skips \"Sales Intern\"). Case and accents are ignored."},"jobTitleIncludeAll":{"type":"boolean","title":"Jobtitleincludeall","description":"Require EVERY `jobTitleInclude` keyword in the title instead of any one.","default":false},"jobDescriptionInclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptioninclude","description":"Keywords the job description must include, each matched anywhere in the description text (`Salesforce` matches a posting asking for \"experience with Salesforce CRM\"). A multi-word keyword must appear with its words in that order. Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobDescriptionIncludeAll`."},"jobDescriptionExclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptionexclude","description":"Keywords the job description must not include: a job is skipped when its description contains any of them anywhere. Case and accents are ignored."},"jobDescriptionIncludeAll":{"type":"boolean","title":"Jobdescriptionincludeall","description":"Require EVERY `jobDescriptionInclude` keyword in the description instead of any one.","default":false},"jobTitleQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitlequery","description":"Advanced: a boolean search string applied to the job title instead of `job_title_include` / `job_title_exclude` (operators: AND, OR, NOT, parentheses, quoted phrases — e.g. `(\"head of marketing\" OR \"VP marketing\") AND NOT intern`). When non-empty, the include/exclude title lists are ignored. Leave null for the simple list-based mode."},"jobDescriptionQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescriptionquery","description":"Advanced: a boolean search string applied to the job description instead of `job_description_include` / `job_description_exclude` (same operator syntax as `job_title_query`). When non-empty, the include/exclude description lists are ignored. Leave null for simple list-based mode."},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Job locations to search, e.g. `[\"France\", \"Belgium\"]`. Applies to the JOB's location, not the hiring company's headquarters: a job in France at a company headquartered abroad matches France. Optional — **leave it empty or omit it to search worldwide**. Multiple locations are OR'd, so adding more widens the search rather than narrowing it. Pass names, not ids (`\"France\"`); unrecognised names are rejected with 400 `INVALID_LOCATION`. A worldwide signal can match far more jobs than a country-scoped one, so set `dailyLeadLimit` to what you actually want delivered. On job signals `dailyLeadLimit` counts companies: each company is delivered at most once a day, however many jobs it posts."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Job locations to exclude from results"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return jobs at companies in these industries. Uses LinkedIn industry names, the same vocabulary as every other signal (e.g. 'Software Development', 'Hospitality', 'Staffing and Recruiting'). Empty = all industries. Call GET /api/v1/signals/industries for the valid list; names must match exactly."},"companyIndustryExcluded":{"items":{"type":"string"},"type":"array","title":"Companyindustryexcluded","description":"Exclude companies in these industries — typically agencies and consultancies posting on a client's behalf. Same LinkedIn industry vocabulary as `industryFilters`. To exclude named companies rather than whole industries, use `excludedWebsites`. Defaults to recruitment agencies and consultancies.","default":["Staffing and Recruiting","Business Consulting and Services"]},"excludedWebsites":{"items":{"type":"string"},"type":"array","title":"Excludedwebsites","description":"Company website domains to exclude from results — e.g. companies you already work with. Accepts domains or URLs (normalized to the bare domain, like 'acme.com'); matching is case-insensitive and ignores 'www.'."},"publishedDate":{"type":"string","title":"Publisheddate","description":"How recently the jobs must have been posted. Use \"24h\", or a count followed by a unit — \"7d\" / \"30d\" (days), \"2w\" (weeks), \"3m\" / \"12m\" (months); the spelled-out forms (\"30 days\", \"3 months\") are accepted too. Defaults to \"30d\" for campaigns.","default":"30d"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"companyOnlyWhenContactsRefused":{"type":"boolean","title":"Companyonlywhencontactsrefused","description":"Deliver the company alone, with no contact, when people were found at it but every one was filtered out by your persona, location or company size settings. Off by default: that company produces nothing, the same as before this option existed. On: you still get the company — priced and delivered exactly like a company-only lead, the same as when nobody at all is found there. Only applies when `enablePersonaTargeting` is on.","default":false},"minJobCount":{"type":"integer","title":"Minjobcount","description":"Minimum number of matching open positions a company must have to qualify. Required when the signal is active.","default":10},"maxJobCount":{"type":"integer","title":"Maxjobcount","description":"Maximum matching open positions; companies with more than this are excluded.","default":1000}},"type":"object","title":"RecruitmentCampaignConfig","description":"Config for recruitment_campaign. Extends job_offers with job count thresholds."},"RecruitmentCampaignCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/RecruitmentCampaignConfig","description":"Signal configuration"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"RecruitmentCampaignCreate","description":"Create a Recruitment Campaign signal.","examples":[{"config":{"companySizeFilters":["201-500","501-1000"],"customPersonaTitles":["People Operations Manager"],"detectTechnologies":false,"enablePersonaTargeting":true,"excludedWebsites":["acme.com"],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"jobDescriptionExclude":[],"jobDescriptionInclude":[],"jobDescriptionIncludeAll":false,"jobTitleExclude":[],"jobTitleInclude":["Engineer","Developer"],"jobTitleIncludeAll":false,"locations":["France"],"maxJobCount":1000,"minJobCount":10,"personaExportMode":"top_ranked","personaLocations":["France"],"publishedDate":"30d","targetPersonas":["HR Director","Talent Acquisition"]},"dailyLeadLimit":50,"name":"Companies hiring aggressively","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"RecruitmentCampaignWatchlistConfig":{"properties":{"sourceType":{"anyOf":[{"type":"string","enum":["csv","hubspot_list","pipedrive_filter","hubspot_company_list","pipedrive_org_filter"]},{"type":"null"}],"title":"Sourcetype","description":"Where the watched list comes from. Omit it to use the list you send inline in this request. Set it to read a list that already exists in your connected CRM instead — the connection itself is made in the dashboard. Call `GET /api/v1/watchlists/sources` for the lists available on your account."},"sourceListId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcelistid","description":"Id of the CRM list or filter to read, as returned by `GET /api/v1/watchlists/sources`. Required when `sourceType` is set, ignored otherwise."},"sourceDynamicSync":{"type":"boolean","title":"Sourcedynamicsync","description":"Keep the watched list in step with the CRM list: entries added there start being watched, entries removed stop. Set false to take a one-off copy at creation and leave it frozen. Has no effect without `sourceType`.","default":true},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"jobTitleInclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleinclude","description":"Keywords the job title must include. Each keyword is matched anywhere in the title, not against the whole title: `sales` matches \"Head of Sales EMEA\". A multi-word keyword must appear with its words in that order (`head of sales` does not match \"Head of Inside Sales\"). Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobTitleIncludeAll`."},"jobTitleExclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleexclude","description":"Keywords the job title must not include: a job is skipped when its title contains any of them anywhere (`intern` skips \"Sales Intern\"). Case and accents are ignored."},"jobTitleIncludeAll":{"type":"boolean","title":"Jobtitleincludeall","description":"Require EVERY `jobTitleInclude` keyword in the title instead of any one.","default":false},"jobDescriptionInclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptioninclude","description":"Keywords the job description must include, each matched anywhere in the description text (`Salesforce` matches a posting asking for \"experience with Salesforce CRM\"). A multi-word keyword must appear with its words in that order. Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobDescriptionIncludeAll`."},"jobDescriptionExclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptionexclude","description":"Keywords the job description must not include: a job is skipped when its description contains any of them anywhere. Case and accents are ignored."},"jobDescriptionIncludeAll":{"type":"boolean","title":"Jobdescriptionincludeall","description":"Require EVERY `jobDescriptionInclude` keyword in the description instead of any one.","default":false},"jobTitleQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitlequery","description":"Advanced: a boolean search string applied to the job title instead of `job_title_include` / `job_title_exclude` (operators: AND, OR, NOT, parentheses, quoted phrases — e.g. `(\"head of marketing\" OR \"VP marketing\") AND NOT intern`). When non-empty, the include/exclude title lists are ignored. Leave null for the simple list-based mode."},"jobDescriptionQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescriptionquery","description":"Advanced: a boolean search string applied to the job description instead of `job_description_include` / `job_description_exclude` (same operator syntax as `job_title_query`). When non-empty, the include/exclude description lists are ignored. Leave null for simple list-based mode."},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Job locations to search, e.g. `[\"France\", \"Belgium\"]`. Applies to the JOB's location, not the hiring company's headquarters: a job in France at a company headquartered abroad matches France. Optional — **leave it empty or omit it to search worldwide**. Multiple locations are OR'd, so adding more widens the search rather than narrowing it. Pass names, not ids (`\"France\"`); unrecognised names are rejected with 400 `INVALID_LOCATION`. A worldwide signal can match far more jobs than a country-scoped one, so set `dailyLeadLimit` to what you actually want delivered. On job signals `dailyLeadLimit` counts companies: each company is delivered at most once a day, however many jobs it posts."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Job locations to exclude from results"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return jobs at companies in these industries. Uses LinkedIn industry names, the same vocabulary as every other signal (e.g. 'Software Development', 'Hospitality', 'Staffing and Recruiting'). Empty = all industries. Call GET /api/v1/signals/industries for the valid list; names must match exactly."},"companyIndustryExcluded":{"items":{"type":"string"},"type":"array","title":"Companyindustryexcluded","description":"Exclude companies in these industries — typically agencies and consultancies posting on a client's behalf. Same LinkedIn industry vocabulary as `industryFilters`. To exclude named companies rather than whole industries, use `excludedWebsites`. Defaults to recruitment agencies and consultancies.","default":["Staffing and Recruiting","Business Consulting and Services"]},"excludedWebsites":{"items":{"type":"string"},"type":"array","title":"Excludedwebsites","description":"Company website domains to exclude from results — e.g. companies you already work with. Accepts domains or URLs (normalized to the bare domain, like 'acme.com'); matching is case-insensitive and ignores 'www.'."},"publishedDate":{"type":"string","title":"Publisheddate","description":"How recently the jobs must have been posted. Use \"24h\", or a count followed by a unit — \"7d\" / \"30d\" (days), \"2w\" (weeks), \"3m\" / \"12m\" (months); the spelled-out forms (\"30 days\", \"3 months\") are accepted too. Defaults to \"30d\" for campaigns.","default":"30d"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"generateAiEmails":{"type":"boolean","title":"Generateaiemails","description":"Generate AI-predicted emails","default":false},"companies":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/WatchedCompanyObject"}]},"type":"array","maxItems":15000,"title":"Companies","description":"The companies to watch. Each entry is either a plain string — a name, a domain, or a LinkedIn company URL (e.g. `\"Doctolib\"`, `\"payfit.com\"`, `\"https://www.linkedin.com/company/lemlist\"`) — or an object `{name, domain, linkedinUrl}` (all optional, at least one required) such as `{\"name\": \"PayFit\", \"domain\": \"payfit.com\", \"linkedinUrl\": \"https://www.linkedin.com/company/payfit\"}`. Both forms can be mixed in one list. Send every identifier you have: each is another way to recognise the company, so an object matches more of your list than any single string. A domain matches most reliably; a name has to match exactly once punctuation and legal suffixes are ignored, so `\"ACME, Inc.\"` and `\"Acme\"` are the same company but `\"Nova\"` and `\"Nova Systems\"` are not.\n\n**Accepted entry forms:** a company name (`\"Doctolib\"`); a domain or website URL (`\"payfit.com\"`, `\"https://www.payfit.com/fr\"`); its LinkedIn company page (`\"https://www.linkedin.com/company/payfit\"`, in any spelling: with or without `https://` and `www.`, a country subdomain, a trailing path or query; school and showcase pages too); its numeric LinkedIn company id (`\"10426145\"`) or a Sales Navigator company link (`\"https://www.linkedin.com/sales/company/10426145\"`), both read as that id; or an object `{name, domain, linkedinUrl}` combining several. Any other LinkedIn link names no company: a person's profile (`/in/`), a post or a group page is refused with 422 `INVALID_COMPANY_ENTRY`, which lists each offending entry, and nothing is saved.\n\nConsumed into the watchlist on create, so it is NOT echoed back in `config` — the watched list has exactly one home. Sent again in a `PATCH`, the entries are ADDED to the list (nothing is removed). Read it with `GET /api/v1/watchlists/{signalId}/companies`, and add, replace or remove entries with `POST` / `DELETE` on the same path."},"companyOnlyWhenContactsRefused":{"type":"boolean","title":"Companyonlywhencontactsrefused","description":"Deliver the company alone, with no contact, when people were found at it but every one was filtered out by your persona, location or company size settings. Off by default: that company produces nothing, the same as before this option existed. On: you still get the company — priced and delivered exactly like a company-only lead, the same as when nobody at all is found there. Only applies when `enablePersonaTargeting` is on.","default":false},"minJobCount":{"type":"integer","title":"Minjobcount","description":"Minimum number of matching open positions a company must have to qualify. Required when the signal is active.","default":10},"maxJobCount":{"type":"integer","title":"Maxjobcount","description":"Maximum matching open positions; companies with more than this are excluded.","default":1000}},"type":"object","title":"RecruitmentCampaignWatchlistConfig","description":"Watch a named list of companies and get told when one starts hiring in volume.\n\nSame filters as the Recruitment Campaign signal, applied to your own list of\naccounts instead of the open market. A company qualifies once it has at\nleast ``minJobCount`` matching roles open inside the ``publishedDate``\nwindow. Companies are given in ``companies`` as a name, a domain, or a\nLinkedIn company URL.","examples":[{"companies":["Doctolib",{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"},"lemlist"],"enablePersonaTargeting":true,"getEmails":true,"maxJobCount":1000,"minJobCount":10,"publishedDate":"30d","targetPersonas":["__best_fitting__"]}]},"RepublishedJobOffersConfig":{"properties":{"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Enable persona-based targeting","default":false},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"Which matched contacts to deliver per company. \"top_ranked\" (default) delivers only the best-ranked contacts — at most 10% of company headcount (minimum 1). \"all_personas\" delivers every matching contact found. \"maxLeadsPerCompany\" caps the total in either mode when set.","default":"top_ranked"},"maxLeadsPerCompany":{"anyOf":[{"type":"integer","maximum":50.0,"minimum":1.0},{"type":"null"}],"title":"Maxleadspercompany","description":"Maximum number of leads to create per company. Overrides the default 10% rule. Set to 1 for strictly one lead per company. On job offer, republished job offer and recruitment campaign signals it is the maximum number of contacts per company per day, and `dailyLeadLimit` counts companies: with a limit of 1 and a maximum of 10, you receive at most 10 contacts from one company per day. A company is delivered at most once a day, however many jobs it posts."},"personaId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personaid","description":"Legacy single persona ID"},"personaLocations":{"items":{"type":"string"},"type":"array","title":"Personalocations","description":"Locations for persona search"},"personaExcludedLocations":{"items":{"type":"string"},"type":"array","title":"Personaexcludedlocations","description":"Locations to exclude from persona search. With only excludes set, every location except these matches; with only includes (personaLocations) set, only those match."},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to target in addition to predefined personas"},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from persona targeting results"},"jobTitleInclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleinclude","description":"Keywords the job title must include. Each keyword is matched anywhere in the title, not against the whole title: `sales` matches \"Head of Sales EMEA\". A multi-word keyword must appear with its words in that order (`head of sales` does not match \"Head of Inside Sales\"). Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobTitleIncludeAll`."},"jobTitleExclude":{"items":{"type":"string"},"type":"array","title":"Jobtitleexclude","description":"Keywords the job title must not include: a job is skipped when its title contains any of them anywhere (`intern` skips \"Sales Intern\"). Case and accents are ignored."},"jobTitleIncludeAll":{"type":"boolean","title":"Jobtitleincludeall","description":"Require EVERY `jobTitleInclude` keyword in the title instead of any one.","default":false},"jobDescriptionInclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptioninclude","description":"Keywords the job description must include, each matched anywhere in the description text (`Salesforce` matches a posting asking for \"experience with Salesforce CRM\"). A multi-word keyword must appear with its words in that order. Case and accents are ignored. Several keywords match when ANY one is found, or ALL of them with `jobDescriptionIncludeAll`."},"jobDescriptionExclude":{"items":{"type":"string"},"type":"array","title":"Jobdescriptionexclude","description":"Keywords the job description must not include: a job is skipped when its description contains any of them anywhere. Case and accents are ignored."},"jobDescriptionIncludeAll":{"type":"boolean","title":"Jobdescriptionincludeall","description":"Require EVERY `jobDescriptionInclude` keyword in the description instead of any one.","default":false},"jobTitleQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobtitlequery","description":"Advanced: a boolean search string applied to the job title instead of `job_title_include` / `job_title_exclude` (operators: AND, OR, NOT, parentheses, quoted phrases — e.g. `(\"head of marketing\" OR \"VP marketing\") AND NOT intern`). When non-empty, the include/exclude title lists are ignored. Leave null for the simple list-based mode."},"jobDescriptionQuery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobdescriptionquery","description":"Advanced: a boolean search string applied to the job description instead of `job_description_include` / `job_description_exclude` (same operator syntax as `job_title_query`). When non-empty, the include/exclude description lists are ignored. Leave null for simple list-based mode."},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Job locations to search, e.g. `[\"France\", \"Belgium\"]`. Applies to the JOB's location, not the hiring company's headquarters: a job in France at a company headquartered abroad matches France. Optional — **leave it empty or omit it to search worldwide**. Multiple locations are OR'd, so adding more widens the search rather than narrowing it. Pass names, not ids (`\"France\"`); unrecognised names are rejected with 400 `INVALID_LOCATION`. A worldwide signal can match far more jobs than a country-scoped one, so set `dailyLeadLimit` to what you actually want delivered. On job signals `dailyLeadLimit` counts companies: each company is delivered at most once a day, however many jobs it posts."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Job locations to exclude from results"},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return jobs at companies in these industries. Uses LinkedIn industry names, the same vocabulary as every other signal (e.g. 'Software Development', 'Hospitality', 'Staffing and Recruiting'). Empty = all industries. Call GET /api/v1/signals/industries for the valid list; names must match exactly."},"companyIndustryExcluded":{"items":{"type":"string"},"type":"array","title":"Companyindustryexcluded","description":"Exclude companies in these industries — typically agencies and consultancies posting on a client's behalf. Same LinkedIn industry vocabulary as `industryFilters`. To exclude named companies rather than whole industries, use `excludedWebsites`. Defaults to recruitment agencies and consultancies.","default":["Staffing and Recruiting","Business Consulting and Services"]},"excludedWebsites":{"items":{"type":"string"},"type":"array","title":"Excludedwebsites","description":"Company website domains to exclude from results — e.g. companies you already work with. Accepts domains or URLs (normalized to the bare domain, like 'acme.com'); matching is case-insensitive and ignores 'www.'."},"publishedDate":{"type":"string","title":"Publisheddate","description":"How far back the signal's FIRST run looks for job offers, and the oldest a delivered offer may be. After the first run the signal follows offers published in the last 7 days, so a longer value adds history once, at the start. Use \"24h\", or a count followed by a unit — \"7d\" / \"30d\" (days), \"2w\" (weeks), \"3m\" / \"12m\" (months). The spelled-out forms (\"7 days\", \"3 months\") are accepted too. Defaults to \"7d\"; an unrecognised value falls back to 7 days.","default":"7d"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"companyOnlyWhenContactsRefused":{"type":"boolean","title":"Companyonlywhencontactsrefused","description":"Deliver the company alone, with no contact, when people were found at it but every one was filtered out by your persona, location or company size settings. Off by default: that company produces nothing, the same as before this option existed. On: you still get the company — priced and delivered exactly like a company-only lead, the same as when nobody at all is found there. Only applies when `enablePersonaTargeting` is on.","default":false}},"type":"object","title":"RepublishedJobOffersConfig","description":"Config for republished_job_offers. Same as JobOffersConfig."},"RepublishedJobOffersCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Name for this signal"},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhookurl","description":"Where each lead is POSTed as it is produced. Optional (since 2026-09-23): omit it when you read leads with GET /api/v1/signals/{signalId}/leads or route them to a connected CRM or sequencer with `destinations` on PATCH /api/v1/signals/{signalId}."},"config":{"$ref":"#/components/schemas/RepublishedJobOffersConfig","description":"Signal configuration (same options as Job Offers)"},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads per day","default":100},"duplicateHandling":{"anyOf":[{"type":"string","pattern":"^(refuse|allow|[0-9]+d)$"},{"type":"null"}],"title":"Duplicatehandling","description":"Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept a duplicate after X days, e.g. '7d'). Optional — defaults to 'allow', so a contact who triggers this signal a second time is delivered a second time.","examples":["7d"]},"status":{"anyOf":[{"type":"string","pattern":"^(draft|active|paused)$"},{"type":"null"}],"title":"Status","description":"Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated."}},"type":"object","required":["name","config"],"title":"RepublishedJobOffersCreate","description":"Create a Republished Job Offers signal.","examples":[{"config":{"companySizeFilters":["201-500","501-1000"],"customPersonaTitles":["VP of Engineering"],"detectTechnologies":false,"enablePersonaTargeting":true,"excludedWebsites":["acme.com"],"getEmails":true,"getHomepageContent":false,"getPhones":false,"getSireneData":false,"jobDescriptionExclude":[],"jobDescriptionInclude":[],"jobDescriptionIncludeAll":false,"jobTitleExclude":[],"jobTitleInclude":["Engineer","Developer"],"jobTitleIncludeAll":false,"locations":["France"],"personaExportMode":"top_ranked","personaLocations":["France"],"publishedDate":"30d","targetPersonas":["CTO","HR Director"]},"dailyLeadLimit":50,"name":"Hard-to-fill engineering roles","status":"active","webhookUrl":"https://your-server.com/webhooks/rodz"}]},"SignalConfigWarning":{"properties":{"code":{"type":"string","title":"Code","description":"Stable identifier. `VALUE_BELOW_MINIMUM` (a value under the documented minimum is applied as the minimum), `VALUE_ADJUSTED` (a value the search cannot use as written is applied as the nearest one it can, e.g. a `publishedDate` of 14d searches 15 days), `FIELD_NOT_USED` (a stored field this signal ignores), `UNKNOWN_SIZE_NOT_ACCEPTED`, `CATEGORY_WITH_OWN_INDUSTRIES` (a category listed together with industries it already covers), `UNKNOWN_INDUSTRY` (a value matching no published industry), `UNKNOWN_FIELD` (a config key this signal does not have), `UNKNOWN_TOOL` / `UNKNOWN_CATEGORY` (a tracked tool or category name that is not in the catalog of GET /api/v1/signals/technographic-tools), `NO_FOLLOWER_SOURCE` (a Company Followers signal with no follower extraction set up yet, so it produces nothing), `DAILY_LIMIT_PENDING` (a job signal's `dailyLeadLimit` changed less than a day after its search was last rebuilt: the search keeps its previous volume until the time in `values`, while the leads delivered per day already follow the new limit), `WATCHED_LIST_EMPTY` (a watchlist reading its list from your CRM holds no company or person — the CRM is not connected, the list could not be read, or it is empty — so it produces nothing until the list fills; cleared on its own once it does), `QUOTE_REQUIRED` (an `active` Company Followers signal in `icp` mode whose follower extraction has not been priced and accepted, so it produces nothing yet: `values[0]` says why — `not_requested`, `awaiting_acceptance` (then `values[1]` is the quoted price in credits), `expired`, `declined`, `failed`, or, after an automatic quote, `auto_quote_refused` / `auto_accept_refused` (then `values[1]` is the error code); the message names the call to make — see POST /api/v1/signals/{signal_id}/extraction/quote; cleared once a quote is accepted), `WATCHED_LIST_IMPORTING` (a company watchlist whose HubSpot list is still being read: companies are added as they arrive; `values[0]` is the number of members read so far, `values[1]` the list id; cleared once the whole list is read), `MATCHING_CONFIRMATION_REQUIRED` (a New Decision Maker or Account watchlist whose companies must be matched to their LinkedIn company page before they can be watched, at a cost above the amount we match without asking: nothing is matched or charged until you confirm with POST /api/v1/watchlists/{signalId}/companies/confirm-matching; `values[0]` is the maximum cost, `values[1]` the number of companies to match; cleared once confirmed), `DESTINATION_UNAVAILABLE` (the outreach campaign this signal sends leads to cannot receive them — not found, archived, ended or without any step — so leads are not reaching it: `values[0]` is `campaign_not_found`, `campaign_archived`, `campaign_ended` or `campaign_no_steps`; cleared once a lead reaches the campaign or the signal's destination is changed), `COMPANY_PAGE_UNAVAILABLE` (a Company Followers signal whose extraction stopped because a page in `linkedinCompanyUrls` does not exist on LinkedIn: nothing was extracted or charged; `values` lists the pages; replace them with PATCH /api/v1/signals/{signal_id}, then start the extraction again; cleared once the pages are replaced or a new extraction runs), `COMPANY_PAGE_UNVERIFIED` (create / PATCH responses only: a page in `linkedinCompanyUrls` could not be verified at that moment and was accepted; `values` lists them — if one does not exist, its extraction stops without using credits and the signal carries `COMPANY_PAGE_UNAVAILABLE`)."},"severity":{"type":"string","title":"Severity","description":"`info`: nothing to do. `warning`: probably not what you meant."},"field":{"type":"string","title":"Field","description":"The `config` key concerned, camelCase (or `dailyLeadLimit`)."},"message":{"type":"string","title":"Message"},"values":{"items":{"type":"string"},"type":"array","title":"Values","description":"The offending values, when there are some."}},"type":"object","required":["code","severity","field","message"],"title":"SignalConfigWarning","description":"One thing about this signal's configuration you should know.","examples":[{"code":"CATEGORY_WITH_OWN_INDUSTRIES","field":"industryFilters","message":"`Manufacturing` is a category, not a single industry: it accepts all 91 industries inside it.","severity":"warning","values":["Manufacturing","Food and Beverage Manufacturing"]}]},"SignalDestinations":{"properties":{"instantly":{"anyOf":[{"$ref":"#/components/schemas/InstantlyDestination"},{"type":"null"}]},"lemlist":{"anyOf":[{"$ref":"#/components/schemas/LemlistDestination"},{"type":"null"}]},"smartlead":{"anyOf":[{"$ref":"#/components/schemas/SmartleadDestination"},{"type":"null"}]},"emelia":{"anyOf":[{"$ref":"#/components/schemas/EmeliaDestination"},{"type":"null"}]},"lgm":{"anyOf":[{"$ref":"#/components/schemas/LgmDestination"},{"type":"null"}]},"gong":{"anyOf":[{"$ref":"#/components/schemas/GongDestination"},{"type":"null"}]},"hubspot":{"anyOf":[{"$ref":"#/components/schemas/EnabledDestination"},{"type":"null"}]},"pipedrive":{"anyOf":[{"$ref":"#/components/schemas/EnabledDestination"},{"type":"null"}]},"googleSheets":{"anyOf":[{"$ref":"#/components/schemas/GoogleSheetsDestination"},{"type":"null"}]},"customWebhook":{"anyOf":[{"$ref":"#/components/schemas/CustomWebhookDestination"},{"type":"null"}]}},"type":"object","title":"SignalDestinations","description":"Where a signal's qualified leads are pushed, in addition to ``webhookUrl``.\n\nEvery provider you name must already be connected on your account — connect the\nAPI-key ones via ``PUT /api/v1/integrations/{provider}``, and the OAuth ones\n(HubSpot, Pipedrive, Google Sheets) once in the dashboard; both are then\nselectable here. Discover campaign / flow / audience ids (and connected-account\nids for multi-account providers like Lemlist) via ``GET /api/v1/integrations``\nand ``GET /api/v1/integrations/{provider}/campaigns``.","examples":[{"hubspot":{"enabled":true},"instantly":{"campaignId":"01920e5f-3c7a-7b1e-9d2f-8a1b2c3d4e5f"}}]},"SmartleadDestination":{"properties":{"campaignId":{"type":"string","title":"Campaignid","description":"Smartlead campaign id."}},"type":"object","required":["campaignId"],"title":"SmartleadDestination","examples":[{"campaignId":"1234567"}]},"SocialMentionsConfig":{"properties":{"postedLimit":{"type":"string","title":"Postedlimit","description":"Time window: \"24h\", \"week\", \"month\"","default":"24h"},"minEngagement":{"type":"integer","title":"Minengagement","description":"Minimum engagement count","default":5},"maxPosts":{"type":"integer","title":"Maxposts","description":"Max posts to process (0 = unlimited)","default":0},"engagementTypes":{"items":{"type":"string","enum":["likes","comments","poster","both"]},"type":"array","title":"Engagementtypes","description":"Which people on each surfaced post become leads. Combine the values in this array:\n- \"likes\": people who reacted to the post.\n- \"comments\": people who commented on the post.\n- \"poster\": the post author. Use [\"poster\"] alone for an author-only signal (no engager fan-out — typically much less noise).\n- \"both\": intersection of likes AND comments (highest intent, smallest volume).\nExamples: [\"likes\", \"comments\"] = union (reacted OR commented); [\"poster\"] = author only; [\"poster\", \"comments\"] = author + commenters.","default":["likes","comments"]},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords","description":"Keywords to track mentions for"},"keywordExclude":{"items":{"type":"string"},"type":"array","title":"Keywordexclude","description":"Exclude posts containing any of these keywords (case-insensitive)"},"includeCompanyAuthors":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Includecompanyauthors","description":"When a company page (not a person) publishes a matching post, also deliver that company as a company-only lead — no contact attached, billed like any lead. Use it to reach brands talking about your topic, not only the people around them. Only applies when `engagementTypes` includes \"poster\". Defaults: on for an author-only signal (`[\"poster\"]`), off when \"poster\" is combined with likes or comments, so a person-lead workflow is not mixed with company rows. Set it explicitly to override either default."}},"type":"object","title":"SocialMentionsConfig","description":"Config for social_mentions — people who posted or commented using given\nkeywords, found by searching LinkedIn content, not by watching a list of\nURLs you supply. Looking for someone who has gone quiet after posting\noften? That is `dormant_linkedin_poster`, a different signal type."},"SocialReactionsConfig":{"properties":{"postedLimit":{"type":"string","title":"Postedlimit","description":"Time window (default \"week\" for reactions)","default":"week"},"minEngagement":{"type":"integer","title":"Minengagement","description":"Minimum engagement count","default":5},"maxPosts":{"type":"integer","title":"Maxposts","description":"Max posts to process (0 = unlimited)","default":0},"engagementTypes":{"items":{"type":"string","enum":["likes","comments","poster","both"]},"type":"array","title":"Engagementtypes","description":"Which people on each surfaced post become leads. Combine the values in this array:\n- \"likes\": people who reacted to the post.\n- \"comments\": people who commented on the post.\n- \"poster\": the post author. Use [\"poster\"] alone for an author-only signal (no engager fan-out — typically much less noise).\n- \"both\": intersection of likes AND comments (highest intent, smallest volume).\nExamples: [\"likes\", \"comments\"] = union (reacted OR commented); [\"poster\"] = author only; [\"poster\", \"comments\"] = author + commenters.","default":["likes","comments"]},"companySizeFilters":{"items":{"type":"string"},"type":"array","title":"Companysizefilters","description":"Company size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\". A company qualifies when its declared size band OR its employee count falls in a selected band; a count within 10% of a band edge counts for both neighbouring bands, and a company declaring 501+ employees is never placed in a smaller band by a low count. The delivered `employee_range` / `employee_count` are the pair the lead was judged on."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"locationFilter":{"type":"string","title":"Locationfilter","description":"Filter by location (e.g. 'France', 'Paris')","default":""},"locations":{"items":{"type":"string"},"type":"array","title":"Locations","description":"Target locations (e.g. ['France', 'Paris']). Applies to the PERSON's LinkedIn profile location, not the company's headquarters: a person in Paris working for a company headquartered abroad matches France. One matching entry is enough. Only fundraising and M&A signals filter on headquarters (`hqLocations`)."},"excludedLocations":{"items":{"type":"string"},"type":"array","title":"Excludedlocations","description":"Locations to exclude from results"},"industryFilters":{"items":{"type":"string"},"type":"array","title":"Industryfilters","description":"Only return companies in these LinkedIn industries. Two kinds of value work: a single industry (e.g. 'Software Development') or a broad category that covers many (e.g. 'Technology and Media'). Matching is exact, so a near-miss like 'Software development' matches nothing and the signal quietly produces no leads. Empty = all industries. Call GET /api/v1/signals/industries for the valid list."},"companyTypeFilters":{"items":{"type":"string"},"type":"array","title":"Companytypefilters","description":"Only return companies of these legal/ownership types. Valid values: 'Privately Held', 'Public Company', 'Nonprofit', 'Educational Institution', 'Partnership', 'Sole Proprietorship', 'Government Agency', 'Self-Employed'. Empty = all types. A company whose type is unknown is KEPT, not dropped, so this narrows results only where the type is known."},"excludedIndustryFilters":{"items":{"type":"string"},"type":"array","title":"Excludedindustryfilters","description":"LinkedIn industries to exclude. Same vocabulary as `industryFilters` (single industry or category name); an unrecognised value excludes nothing. Call GET /api/v1/signals/industries for the valid list."},"excludedCompanyUrls":{"items":{"type":"string"},"type":"array","title":"Excludedcompanyurls","description":"LinkedIn company URLs to exclude from results"},"excludedCompanySizeFilters":{"items":{"type":"string"},"type":"array","title":"Excludedcompanysizefilters","description":"Company sizes to exclude from results"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Custom free-text job titles to match in addition to predefined personas. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level."},"excludedTitles":{"items":{"type":"string"},"type":"array","title":"Excludedtitles","description":"Job titles to exclude from results"},"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"postUrls":{"items":{"type":"string"},"type":"array","title":"Posturls","description":"LinkedIn post URLs to track reactions on (required for activation). Short links (https://lnkd.in/…) are accepted and stored as the full post URL they point to; the query string (tracking parameters) is dropped."}},"type":"object","title":"SocialReactionsConfig","description":"Config for social_reactions — people who reacted to specific POST URLs you\nsupply. Not for watching a person's or a company's whole post history\n(`company_engagement`, `company_post_reactions`), and not for finding\npeople who stopped posting (`dormant_linkedin_poster`)."},"TechAdoptionConfig":{"properties":{"getEmails":{"type":"boolean","title":"Getemails","description":"Enable email enrichment (0.5 credit/lead, charged only on success)","default":false},"getPhones":{"type":"boolean","title":"Getphones","description":"Enable phone enrichment (5 credits/lead, charged only on success)","default":false},"getSireneData":{"type":"boolean","title":"Getsirenedata","description":"Enrich with French SIRENE registry data (1 credit/lead, charged only on success)","default":false},"detectTechnologies":{"type":"boolean","title":"Detecttechnologies","description":"Detect technologies used on the company's public website (1 credit/lead, charged only on success)","default":false},"getHomepageContent":{"type":"boolean","title":"Gethomepagecontent","description":"Fetch the company's homepage content (1 credit/lead, charged only on success)","default":false},"trackedTool":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trackedtool","description":"Exact tool name to watch for new adoptions — use the `vendorName` value from GET /api/v1/signals/technographic-tools (copy it verbatim; a near-miss matches nothing). Provide this OR trackedCategory."},"trackedCategory":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trackedcategory","description":"Watch adoptions of ANY tool in this category. Provide this OR trackedTool."},"companyEmployeeSizeRanges":{"items":{"type":"string"},"type":"array","title":"Companyemployeesizeranges","description":"Employee-size filter. Values: \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"."},"companyIndustries":{"items":{"type":"string"},"type":"array","title":"Companyindustries","description":"Industry filter — use exact values from GET /api/v1/signals/technographic-industries (e.g. 'Financial Services', 'Software Development'). An unrecognised value is not rejected, it just matches nothing."},"companyCountries":{"items":{"type":"string"},"type":"array","title":"Companycountries","description":"Country filter — ISO 3166-1 alpha-2 codes (e.g. 'US', 'FR', 'GB')."},"companyRegion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Companyregion","description":"Geographic region filter (e.g. 'Europe', 'North America')."},"excludeDomains":{"items":{"type":"string"},"type":"array","title":"Excludedomains","description":"Company domains to exclude (e.g. your existing customers)."},"targetPersonas":{"items":{"type":"string"},"type":"array","title":"Targetpersonas","description":"Filter by job-role persona (decision-maker targeting). Accepted values are the persona display names listed here; see GET /v1/personas for the full taxonomy with department, seniority and EN/FR job titles. Titles are matched by meaning, not as text: `targetPersonas` and `customPersonaTitles` form ONE list and a person qualifies by matching ANY entry. Each entry is read as a function plus a seniority level, in any language (\"Directeur Commercial\" satisfies \"Sales Director\", \"Président\" or \"Directeur général\" a CEO target), and a role at that level or above qualifies: a Director or Head target refuses a plain Manager; a founder running the company counts as CEO. A custom title carries the level its own words state; one with no level word accepts every level. Valid values: \"Account Executive\", \"Account Manager\", \"Accountant\", \"Agency Director\", \"Business Analyst\", \"Business Developer\", \"Business Unit Director\", \"Buyer\", \"CEO\", \"CIO\", \"CSR Director\", \"CSR Manager\", \"CTO\", \"Communication Director\", \"Community Manager\", \"Content Manager\", \"Copywriter\", \"Creative Director\", \"Customer Success Director\", \"Customer Success Manager\", \"Customer Support Agent\", \"Cybersecurity Director\", \"Data Analyst\", \"Data Director\", \"Designer\", \"DevOps Engineer\", \"Digital Director\", \"Digital Project Manager\", \"Ecommerce Director\", \"Ecommerce Manager\", \"Engineering Manager\", \"Engineering Office Director\", \"Ergonomist\", \"Executive Assistant\", \"Finance Director\", \"Finance Manager\", \"GTM Director\", \"GTM Manager\", \"Growth Director\", \"Growth Manager\", \"HR Assistant\", \"HR Development\", \"HR Director\", \"Happiness Manager\", \"IT Project Manager\", \"Industrial Director\", \"Innovation Director\", \"Lab Manager\", \"Legal Counsel\", \"Legal Director\", \"Legal Manager\", \"Logistics Coordinator\", \"Logistics Director\", \"M&A Director\", \"Marketing Director\", \"Marketing Manager\", \"Office Manager\", \"Omnichannel Director\", \"Operations Director\", \"Operations Manager\", \"Payroll Manager\", \"Payroll Officer\", \"Procurement Specialist\", \"Product Director\", \"Product Manager\", \"Project Manager\", \"Purchasing Director\", \"Purchasing Manager\", \"Quality Health and Safety\", \"Quality Manager\", \"Quality Technician\", \"R&D Director\", \"R&D Engineer\", \"R&D Manager\", \"Recruitment Manager\", \"Research Director\", \"Research Scientist\", \"SDR / BDR\", \"Sales Director\", \"Sales Manager\", \"Social Media Director\", \"Social Media Manager\", \"Software Engineer\", \"Supply Chain Director\", \"Support Director\", \"Support Manager\", \"Talent Acquisition\", \"Technical Director\", \"Training Director\", \"Training Officer\", \"Transformation Director\", \"UX Designer\", \"Warehouse Director\", \"Web Developer\""},"enablePersonaTargeting":{"type":"boolean","title":"Enablepersonatargeting","description":"Find the people matching `targetPersonas` at each company that triggers the signal. Off = company-only leads.","default":false},"personaExportMode":{"type":"string","title":"Personaexportmode","description":"`top_ranked` delivers the single best-matching person per company; `all_personas` delivers one lead per matching persona.","default":"top_ranked"},"customPersonaTitles":{"items":{"type":"string"},"type":"array","title":"Custompersonatitles","description":"Extra job titles to match, alongside the preset personas."},"maxLeadsPerCompany":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Maxleadspercompany","description":"Cap on people delivered per company. Empty = no cap."},"dailyLeadLimit":{"type":"integer","maximum":999999.0,"minimum":1.0,"title":"Dailyleadlimit","description":"Max leads/day. Caps how many adoption events are collected per day — never more.","default":20}},"type":"object","title":"TechAdoptionConfig","description":"Tech Adoption signal — fires when a company STARTS using a tracked tool.\n\nEvery filter below is applied at the SEARCH itself, so a company that fails\nany of them is never returned. That is\nwhy the usual company_size_filters / locations / industry_filters are not\noffered here: those can only disqualify a company after it has been found,\nwhile the filters below narrow the search before it runs. Persona lookup and\nemail/phone stay as optional add-ons, applied only to companies the search\nreturned.","examples":[{"companyCountries":["US","GB"],"companyEmployeeSizeRanges":["51-200","201-500"],"companyIndustries":["Financial Services"],"enablePersonaTargeting":true,"getEmails":true,"targetPersonas":["Head of Engineering"],"trackedTool":"Cursor"}]},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WatchedCompanyObject":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Name","description":"The company name as you know it, e.g. `\"PayFit\"`."},"domain":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Domain","description":"The company website, e.g. `\"payfit.com\"`. A full URL is accepted and reduced to its domain."},"linkedinUrl":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Linkedinurl","description":"The company LinkedIn page, e.g. `\"https://www.linkedin.com/company/payfit\"`. The most precise identifier of the three. A Sales Navigator company link (`/sales/company/<id>`) or the numeric LinkedIn company id is accepted too, and so are school and showcase pages; any other LinkedIn link (a person's profile, a post) is refused with 422 `INVALID_COMPANY_ENTRY`."}},"additionalProperties":false,"type":"object","title":"WatchedCompanyObject","description":"One company, with everything you know about it.\n\nThe object form of a company-list entry. Send every identifier you have:\neach one is another way to recognise the company, and together they\nseparate two companies that share a name.","examples":[{"domain":"payfit.com","linkedinUrl":"https://www.linkedin.com/company/payfit","name":"PayFit"}]},"WatchedProfileSeed":{"properties":{"url":{"type":"string","title":"Url","description":"LinkedIn profile URL of the person to watch."},"currentTitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currenttitle","description":"Their job title as you have it on file — the comparison point."},"currentCompany":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currentcompany","description":"Their employer as you have it on file — the comparison point."},"currentCompanyUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currentcompanyurl","description":"Their employer's LinkedIn company URL, if you have it."}},"type":"object","required":["url"],"title":"WatchedProfileSeed","description":"A person to watch, with the role you already have on file for them.\n\n`{url, currentTitle, currentCompany, currentCompanyUrl}` — only `url` is\nrequired. Send the role whenever your CRM has it: it is the comparison point\nfor the FIRST check, so a move made at any time since you recorded that role\nis reported straight away. With a bare URL the first check can only report a\nmove made in the last 6 months; anyone who moved earlier is recorded as they\nstand today and reported only on their next move.","examples":[{"currentCompany":"Doctolib","currentCompanyUrl":"https://www.linkedin.com/company/doctolib","currentTitle":"VP Sales","url":"https://www.linkedin.com/in/marie-dupont"}]},"WebhookCompanyFull":{"properties":{"name":{"type":"string","title":"Name","description":"Company name","default":""},"website":{"type":"string","title":"Website","description":"Company website","default":""},"linkedin_url":{"type":"string","title":"Linkedin Url","description":"Company LinkedIn URL","default":""},"hq_country_code":{"type":"string","title":"Hq Country Code","description":"Country of the company headquarters, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"hq_city":{"type":"string","title":"Hq City","description":"City of the company headquarters (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"tech_stack":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Tech Stack","description":"Detected technologies (if enrichment enabled); \"\" when absent"},"homepage_title":{"type":"string","title":"Homepage Title","description":"Company homepage title (if enrichment enabled)","default":""},"meta_description":{"type":"string","title":"Meta Description","description":"Company homepage meta description (if enrichment enabled)","default":""},"description":{"type":"string","title":"Description","description":"Short company description (if available)","default":""},"industry":{"type":"string","title":"Industry","description":"Company industry","default":""},"location":{"type":"string","title":"Location","description":"Company HQ location","default":""},"employee_count":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Employee Count","description":"Head count the lead was qualified on, when a head count (not only a band) was known; \"\" otherwise","default":""},"employee_range":{"type":"string","title":"Employee Range","description":"Company size band the lead was qualified on - one of \"Self-employed\", \"1-10\", \"11-50\", \"51-200\", \"201-500\", \"501-1000\", \"1001-5000\", \"5001-10000\", \"10001+\"","default":""},"headquarters":{"type":"string","title":"Headquarters","description":"Registered head office, \"City, CC\" (e.g. \"Paris, FR\"); \"\" when absent","default":""},"company_type":{"type":"string","title":"Company Type","description":"Company type (e.g. \"Privately Held\", \"Public Company\"); \"\" when absent","default":""},"founded_year":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Founded Year","description":"Year the company was founded; \"\" when absent","default":""}},"type":"object","title":"WebhookCompanyFull","description":"Full company info (company-only signals: job_offers, fundraising, etc.)."},"WebhookContact":{"properties":{"lead_id":{"type":"string","title":"Lead Id","description":"UUID of the lead"},"created_at":{"type":"string","title":"Created At","description":"ISO 8601 timestamp"},"first_name":{"type":"string","title":"First Name","description":"Contact first name","default":""},"last_name":{"type":"string","title":"Last Name","description":"Contact last name","default":""},"email":{"type":"string","title":"Email","description":"Email (if enrichment enabled)","default":""},"phone":{"type":"string","title":"Phone","description":"Phone (if enrichment enabled)","default":""},"title":{"type":"string","title":"Title","description":"Job title. On social signals (mentions, reactions, engagement) this is the person's LinkedIn headline as shown on the post.","default":""},"location":{"type":"string","title":"Location","description":"Location","default":""},"country_code":{"type":"string","title":"Country Code","description":"Country of `location`, ISO 3166-1 alpha-2 (e.g. \"FR\"); \"\" when it could not be determined","default":""},"city":{"type":"string","title":"City","description":"City of `location` (e.g. \"Paris\"); \"\" when it could not be determined","default":""},"linkedin_profile_url":{"type":"string","title":"Linkedin Profile Url","description":"LinkedIn profile URL","default":""},"sales_navigator_profile_url":{"type":"string","title":"Sales Navigator Profile Url","description":"Sales Navigator profile URL","default":""},"matched_persona":{"type":"string","title":"Matched Persona","description":"Matched persona name (if persona filter configured)","default":""}},"type":"object","required":["lead_id","created_at"],"title":"WebhookContact","description":"Contact/person data. Present for person-based signals; the parent\n``contact`` key is the empty string ``\"\"`` for company-only leads with no\ncontact. Individual fields are empty strings when not available."},"WebhookFundraisingPayload":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookFundraisingSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookFundraisingPayload","description":"Webhook payload for fundraising signals.\n\nAll documented keys are always present. Absent values are delivered as empty\nstrings (``\"\"``), never ``null``. In particular ``contact`` is the empty\nstring ``\"\"`` unless persona targeting is enabled, in which case it is a\ncontact object.","examples":[{"company":{"hq_city":"Paris","hq_country_code":"FR","industry":"SaaS","linkedin_url":"https://linkedin.com/company/fundedstartup","location":"Paris, France","name":"Funded Startup","website":"https://fundedstartup.com"},"contact":"","signal":{"announcement_date":"2026-01-15","article_source_url":"https://techcrunch.com/2026/01/15/funded-startup-raises-5m-series-a","article_summary":"Funded Startup raised a €5M Series A to expand its AI-powered SaaS platform across European markets. The round was led by VC Fund Alpha.","article_use_of_funds":"Product development, hiring 20 engineers, and expansion into Germany and UK markets.","company_crunchbase_url":"https://example.com/organization/funded-startup","funding_amount":5000000,"funding_amount_usd":5500000,"funding_currency":"EUR","funding_stage":"Series A","funding_total_usd":8200000,"funding_type":"venture","id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","investors":["VC Fund Alpha","Angel Investor"],"last_signal":"Fundraising","last_signal_date":"2026-02-24","name":"Series A+ in France","num_investors":2,"type":"fundraising"}}]},"WebhookFundraisingSignal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"funding_type":{"type":"string","title":"Funding Type","description":"Round type (e.g. \"venture\", \"seed\")","default":""},"funding_stage":{"type":"string","title":"Funding Stage","description":"Stage (e.g. \"Series A\")","default":""},"funding_amount":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount","description":"Amount in original currency; \"\" when absent","default":""},"funding_amount_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Amount Usd","description":"Amount in USD; \"\" when absent","default":""},"funding_currency":{"type":"string","title":"Funding Currency","description":"ISO currency code","default":""},"investors":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"string"}],"title":"Investors","description":"List of investor names; \"\" when absent"},"num_investors":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Num Investors","description":"Number of investors participating in the round; \"\" when absent","default":""},"funding_total_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Funding Total Usd","description":"Total the company has raised to date in USD, across all rounds — not just this one; \"\" when absent","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD)","default":""},"company_crunchbase_url":{"type":"string","title":"Company Crunchbase Url","description":"Public funding profile URL","default":""},"article_summary":{"type":"string","title":"Article Summary","description":"AI-generated summary of the funding announcement article","default":""},"article_use_of_funds":{"type":"string","title":"Article Use Of Funds","description":"AI-extracted planned use of funds from the article","default":""},"article_source_url":{"type":"string","title":"Article Source Url","description":"URL of the source article about the funding round","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookFundraisingSignal","description":"Signal info for fundraising signals."},"WebhookJobSignal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"job_offer_url":{"type":"string","title":"Job Offer Url","description":"Link to the job posting; \"\" when there is no public link","default":""},"job_offer_title":{"type":"string","title":"Job Offer Title","description":"Job title","default":""},"job_offer_location":{"type":"string","title":"Job Offer Location","description":"Job location","default":""},"job_offer_description":{"type":"string","title":"Job Offer Description","description":"Job description excerpt","default":""},"job_offer_date":{"type":"string","title":"Job Offer Date","description":"Job publication date as the posting states it: a day (`2026-09-12`) or a timestamp (`2026-09-12T07:48:45Z`). Read `job_offer_published_date` for one fixed format.","default":""},"job_offer_published_date":{"type":"string","title":"Job Offer Published Date","description":"Job publication day, always `YYYY-MM-DD` — the date the opening went live, not the day we delivered it (`last_signal_date`). \"\" when the posting states no date.","default":""},"job_offer_source":{"type":"string","title":"Job Offer Source","description":"Job source platform (e.g. \"LinkedIn\", \"Indeed\")","default":""},"matched_keywords":{"type":"string","title":"Matched Keywords","description":"Comma-separated keywords that matched this job","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookJobSignal","description":"Signal info for job-based signals (job_offers, republished_job_offers, recruitment_campaign)."},"WebhookMergersAcquisitionsPayload":{"properties":{"signal":{"$ref":"#/components/schemas/WebhookMergersAcquisitionsSignal"},"contact":{"anyOf":[{"$ref":"#/components/schemas/WebhookContact"},{"type":"string"}],"title":"Contact","description":"Empty string \"\" unless persona targeting is enabled; then a contact object. Always present — never null."},"company":{"$ref":"#/components/schemas/WebhookCompanyFull"}},"type":"object","required":["signal","company"],"title":"WebhookMergersAcquisitionsPayload","description":"Webhook payload for M&A signals.\n\nAll documented keys are always present. Absent values are delivered as empty\nstrings (``\"\"``), never ``null``. In particular ``contact`` is the empty\nstring ``\"\"`` unless persona targeting is enabled, in which case it is a\ncontact object.","examples":[{"company":{"hq_city":"Paris","hq_country_code":"FR","industry":"SaaS","linkedin_url":"https://linkedin.com/company/acquiredstartup","location":"Paris, France","name":"Acquired Startup","website":"https://acquiredstartup.com"},"contact":"","signal":{"acquiree_crunchbase_url":"https://example.com/organization/acquired-startup","acquiree_industries":"SaaS","acquiree_location":"Paris, France","acquiree_name":"Acquired Startup","acquiree_website":"https://acquiredstartup.com","acquirer_crunchbase_url":"https://example.com/organization/big-corp","acquirer_industries":"Enterprise Software","acquirer_location":"New York, USA","acquirer_name":"Big Corp","acquirer_website":"https://bigcorp.com","acquisition_type":"acquisition","announcement_date":"2026-01-15","article_acquisition_rationale":"Strategic acquisition to integrate Acquired Startup's AI technology into Big Corp's existing enterprise product suite.","article_source_url":"https://techcrunch.com/2026/01/15/big-corp-acquires-startup","article_summary":"Big Corp acquired Acquired Startup for €10M to strengthen its AI capabilities in the enterprise SaaS market.","deal_price_currency":"EUR","deal_price_usd":10000000,"id":"d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8","last_signal":"Mergers & Acquisitions","last_signal_date":"2026-02-24","name":"SaaS acquisitions","type":"mergers_acquisitions"}}]},"WebhookMergersAcquisitionsSignal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"acquiree_name":{"type":"string","title":"Acquiree Name","description":"Acquired company name","default":""},"acquiree_website":{"type":"string","title":"Acquiree Website","description":"Acquired company website","default":""},"acquiree_industries":{"type":"string","title":"Acquiree Industries","description":"Acquired company industries","default":""},"acquiree_location":{"type":"string","title":"Acquiree Location","description":"Acquired company HQ location","default":""},"acquiree_crunchbase_url":{"type":"string","title":"Acquiree Crunchbase Url","description":"Acquired company public profile URL","default":""},"acquirer_name":{"type":"string","title":"Acquirer Name","description":"Acquiring company name","default":""},"acquirer_website":{"type":"string","title":"Acquirer Website","description":"Acquiring company website","default":""},"acquirer_industries":{"type":"string","title":"Acquirer Industries","description":"Acquiring company industries","default":""},"acquirer_location":{"type":"string","title":"Acquirer Location","description":"Acquiring company HQ location","default":""},"acquirer_crunchbase_url":{"type":"string","title":"Acquirer Crunchbase Url","description":"Acquiring company public profile URL","default":""},"acquisition_type":{"type":"string","title":"Acquisition Type","description":"Deal type (e.g. \"acquisition\", \"merger\")","default":""},"deal_price_usd":{"anyOf":[{"type":"number"},{"type":"string"}],"title":"Deal Price Usd","description":"Deal price in USD; \"\" when absent","default":""},"deal_price_currency":{"type":"string","title":"Deal Price Currency","description":"Deal price currency code","default":""},"announcement_date":{"type":"string","title":"Announcement Date","description":"Announcement date (YYYY-MM-DD)","default":""},"article_summary":{"type":"string","title":"Article Summary","description":"AI-generated summary of the M&A deal article","default":""},"article_acquisition_rationale":{"type":"string","title":"Article Acquisition Rationale","description":"AI-extracted rationale for the acquisition","default":""},"article_source_url":{"type":"string","title":"Article Source Url","description":"URL of the source article about the deal","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookMergersAcquisitionsSignal","description":"Signal info for mergers & acquisitions signals."},"WebhookPersonSignal":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the signal"},"name":{"type":"string","title":"Name","description":"User-defined signal name"},"type":{"type":"string","title":"Type","description":"Signal type ID (e.g. 'competitor_relationship_monitoring')"},"last_signal":{"type":"string","title":"Last Signal","description":"Human-readable signal label"},"last_signal_date":{"type":"string","title":"Last Signal Date","description":"Date of detection (YYYY-MM-DD)"},"tracked_company":{"type":"string","title":"Tracked Company","description":"Tracked LinkedIn company URL","default":""}},"type":"object","required":["id","name","type","last_signal","last_signal_date"],"title":"WebhookPersonSignal","description":"Signal info for person-based signals (competitor_relationship_monitoring, job_changes)."}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key from Integrations → API in the dashboard (e.g. USR_xxxxxxxxxxxxx)"}}},"security":[{"BearerAuth":[]}],"webhooks":{"signal.action_required":{"post":{"summary":"A signal is waiting on you","description":"Know the moment a signal stops producing until you act — and act from your own system. Some signals need your yes before they spend credits: a New Decision Maker or Account watchlist whose companies must be matched to their LinkedIn company page at a cost above what we match without asking (`MATCHING_CONFIRMATION_REQUIRED`), and a Company Followers signal in `icp` mode whose follower extraction must be quoted and accepted (`QUOTE_REQUIRED`). A Company Followers signal can also stop because a LinkedIn company page it names does not exist (`COMPANY_PAGE_UNAVAILABLE`): nothing is charged, and `apiEndpoint` is the PATCH that replaces the page. That state often appears after you created the signal — once a large company list has been read, once a quote is ready — so this event tells you instead of leaving you to poll.\n\n**When:** once per ask (a new quote is a new ask), after we review it. At the same time the account owners get an email with the quote and a link to confirm in the dashboard, and one reminder email 3 days later if it is still pending; the event itself is not repeated.\n\n**Output:** `event`, `eventId`, `signalId`, `signalName`, `signalTypeId`, `code`, `createdAt`, `message`, `quote` (the price of saying yes), `confirmUrl` (dashboard) and `apiEndpoint` (`method`, `url`, `body` of the call that unblocks it).\n\n**Use cases:**\n- Approve automatically under your own budget: call `apiEndpoint` when `quote.estimatedCost` (or `quote.credits`) is below your threshold.\n- Route the decision to a person: post `message` and `confirmUrl` to the account owner's Slack or ticket queue.\n- Keep your UI honest: show the signal as \"waiting on you\" until `signal.action_resolved` arrives. `GET /api/v1/signals?actionRequired=true` gives the same list on demand.\n\nYour signal's `webhookUrl` receives leads, and also these events. Every event carries a top-level `event` key, which no lead has: route on it, and ignore event types you do not handle — new ones may be added. Signed exactly like leads (`X-Webhook-Signature`, `X-Webhook-Timestamp`) when the signal has a webhook secret. An event is not a lead: it is free and never counted as a delivered lead.","tags":["Signals"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"description":"Sent to the signal's `webhookUrl` when the signal starts waiting on you.","examples":[{"apiEndpoint":{"body":{"confirm":true},"method":"POST","url":"https://api.rodz.io/api/v1/watchlists/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/companies/confirm-matching"},"code":"MATCHING_CONFIRMATION_REQUIRED","confirmUrl":"https://app.rodz.io/signals/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/configure","createdAt":"2026-10-09T09:16:02+00:00","event":"signal.action_required","eventId":"5f0c2a4e-8b1d-4c3e-9a7f-2d6e1b0c9a84","message":"12,000 companies on this list must be matched to their LinkedIn company page before they can be watched, for at most 600.0 credits (0.05 per company; companies already matched are free). Nothing is matched or charged until you confirm with POST /api/v1/watchlists/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/companies/confirm-matching and {\"confirm\": true}.","quote":{"alreadyMatchedFree":0,"billableCompanies":12000,"companiesToMatch":12000,"confirmationRequired":true,"currency":"credits","estimatedCost":600.0,"isUpperBound":true,"pricePerCompany":0.05,"status":"awaiting_confirmation","sufficientBalance":true},"signalId":"d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f","signalName":"Key accounts - new decision makers","signalTypeId":"new_decision_maker_watchlist"}],"properties":{"event":{"description":"Always `signal.action_required`.","title":"Event","type":"string"},"eventId":{"description":"Unique id of this ask. Also sent as the `X-Webhook-Id` header; use it to ignore a duplicate delivery.","title":"Eventid","type":"string"},"signalId":{"description":"The signal waiting on you.","title":"Signalid","type":"string"},"signalName":{"description":"Its name.","title":"Signalname","type":"string"},"signalTypeId":{"description":"Its type, e.g. `new_decision_maker_watchlist`.","title":"Signaltypeid","type":"string"},"code":{"description":"What it waits for: `MATCHING_CONFIRMATION_REQUIRED` (a New Decision Maker or Account watchlist whose companies must be matched to their LinkedIn company page, at a cost that needs your confirmation), `QUOTE_REQUIRED` (a Company Followers signal in `icp` mode whose follower extraction must be quoted and the quote accepted) or `COMPANY_PAGE_UNAVAILABLE` (a Company Followers signal whose extraction stopped because a LinkedIn company page in `linkedinCompanyUrls` does not exist: replace the page). The same code as in the signal's `warnings`.","title":"Code","type":"string"},"createdAt":{"description":"When the event was sent, ISO 8601 UTC.","title":"Createdat","type":"string"},"message":{"description":"The same plain-language explanation as the signal's warning.","title":"Message","type":"string"},"quote":{"additionalProperties":true,"description":"The price of saying yes. For `MATCHING_CONFIRMATION_REQUIRED`: the response of POST /api/v1/watchlists/{signalId}/companies/confirm-matching with `confirm: false` (`companiesToMatch`, `alreadyMatchedFree`, `billableCompanies`, `pricePerCompany`, `currency`, `estimatedCost` — an upper bound — `sufficientBalance`, ...). For `QUOTE_REQUIRED`: `state` (`awaiting_acceptance`, `not_requested`, `expired` or `failed`), `credits` and `followers` of the quote waiting for acceptance (else `null`), `expiresAt` and `currency`. For `COMPANY_PAGE_UNAVAILABLE`: `state` (`company_page_unavailable`), `companyUrls` (the pages that do not exist; empty when we cannot tell which of the signal's pages it is), `credits` (always `0`: nothing was charged) and `currency`.","examples":[{"alreadyMatchedFree":0,"billableCompanies":12000,"companiesToMatch":12000,"confirmationRequired":true,"currency":"credits","estimatedCost":600.0,"isUpperBound":true,"pricePerCompany":0.05,"status":"awaiting_confirmation","sufficientBalance":true},{"credits":1250,"currency":"credits","expiresAt":"2026-11-08T10:00:00+00:00","followers":3400,"state":"awaiting_acceptance"}],"title":"Quote","type":"object"},"confirmUrl":{"description":"The dashboard page that shows the quote with its confirm button.","title":"Confirmurl","type":"string"},"apiEndpoint":{"description":"The call that unblocks the signal.","examples":[{"body":{"confirm":true},"method":"POST","url":"https://api.rodz.io/api/v1/watchlists/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/companies/confirm-matching"}],"properties":{"method":{"description":"HTTP method, `POST`.","title":"Method","type":"string"},"url":{"description":"Full URL of the call, with your signal id in it.","title":"Url","type":"string"},"body":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"default":null,"description":"JSON body to send, or `null` when the call takes none.","title":"Body"}},"required":["method","url"],"title":"SignalEventApiEndpoint","type":"object"}},"required":["event","eventId","signalId","signalName","signalTypeId","code","createdAt","message","quote","confirmUrl","apiEndpoint"],"title":"SignalActionRequiredEvent","type":"object"},"example":{"event":"signal.action_required","eventId":"5f0c2a4e-8b1d-4c3e-9a7f-2d6e1b0c9a84","signalId":"d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f","signalName":"Key accounts - new decision makers","signalTypeId":"new_decision_maker_watchlist","code":"MATCHING_CONFIRMATION_REQUIRED","createdAt":"2026-10-09T09:16:02+00:00","message":"12,000 companies on this list must be matched to their LinkedIn company page before they can be watched, for at most 600.0 credits (0.05 per company; companies already matched are free). Nothing is matched or charged until you confirm with POST /api/v1/watchlists/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/companies/confirm-matching and {\"confirm\": true}.","quote":{"status":"awaiting_confirmation","companiesToMatch":12000,"alreadyMatchedFree":0,"billableCompanies":12000,"pricePerCompany":0.05,"currency":"credits","estimatedCost":600.0,"isUpperBound":true,"sufficientBalance":true,"confirmationRequired":true},"confirmUrl":"https://app.rodz.io/signals/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/configure","apiEndpoint":{"method":"POST","url":"https://api.rodz.io/api/v1/watchlists/d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f/companies/confirm-matching","body":{"confirm":true}}}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Other answers are recorded in your webhook deliveries; they never pause lead delivery."}}}},"signal.action_resolved":{"post":{"summary":"A signal no longer waits on you","description":"Close the loop on a `signal.action_required`: the signal no longer waits on you — you confirmed or accepted, or the signal was paused or deleted.\n\n**Output:** `event`, `eventId`, `signalId`, `signalName`, `signalTypeId`, `code` (the code of the ask it closes) and `createdAt`.\n\nYour signal's `webhookUrl` receives leads, and also these events. Every event carries a top-level `event` key, which no lead has: route on it, and ignore event types you do not handle — new ones may be added. Signed exactly like leads (`X-Webhook-Signature`, `X-Webhook-Timestamp`) when the signal has a webhook secret. An event is not a lead: it is free and never counted as a delivered lead.","tags":["Signals"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"description":"Sent when a signal that waited on you no longer does.","examples":[{"code":"MATCHING_CONFIRMATION_REQUIRED","createdAt":"2026-10-09T11:02:40+00:00","event":"signal.action_resolved","eventId":"9e1d7c3b-2a4f-4b6e-8d0c-1f5a3e7b9c26","signalId":"d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f","signalName":"Key accounts - new decision makers","signalTypeId":"new_decision_maker_watchlist"}],"properties":{"event":{"description":"Always `signal.action_resolved`.","title":"Event","type":"string"},"eventId":{"description":"Unique id of this event (`X-Webhook-Id`).","title":"Eventid","type":"string"},"signalId":{"title":"Signalid","type":"string"},"signalName":{"title":"Signalname","type":"string"},"signalTypeId":{"title":"Signaltypeid","type":"string"},"code":{"description":"The code of the `signal.action_required` it closes.","title":"Code","type":"string"},"createdAt":{"description":"When the event was sent, ISO 8601 UTC.","title":"Createdat","type":"string"}},"required":["event","eventId","signalId","signalName","signalTypeId","code","createdAt"],"title":"SignalActionResolvedEvent","type":"object"},"example":{"event":"signal.action_resolved","eventId":"9e1d7c3b-2a4f-4b6e-8d0c-1f5a3e7b9c26","signalId":"d4bab73d-5c1e-4b7a-9f2e-3a6b8c0d1e2f","signalName":"Key accounts - new decision makers","signalTypeId":"new_decision_maker_watchlist","code":"MATCHING_CONFIRMATION_REQUIRED","createdAt":"2026-10-09T11:02:40+00:00"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the event. Other answers are recorded in your webhook deliveries; they never pause lead delivery."}}}}}}