Signals

Create Recruitment Campaign Watchlist signal

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.

Two 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.

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, requireContact - default false; true = only leads with a contact: a company where nobody matching your personas is found is neither delivered nor charged) and enrichment flags (getEmails, getPhones).

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.

Only 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.

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.

Use cases:

  • 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.
  • 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.
  • 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.
  • Competitor momentum - a competitor staffing a whole function tells you where they are betting, early enough to answer it.
post/api/v1/signals/recruitment-campaign-watchlist

Request

  • Base URL: https://api.rodz.io (the document declares no server; this is the origin it was published from)
  • URL: https://api.rodz.io/api/v1/signals/recruitment-campaign-watchlist
  • Auth: HTTP bearer

Request body

namestring required

Name for this signal

webhookUrlstring nullable

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}.

dailyLeadLimitinteger

Max leads per day

statusstring nullable

Initial status (default: draft).

Example request

{
  "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"
}

Response

Signal created

idstring required
namestring required
statusstring required
signalTypeIdstring required
webhookUrlstring nullable
configobject nullable

Signal-specific configuration

dailyLeadLimitinteger required
leadsTodayinteger required
leadsTotalinteger required
duplicateHandlingstring required

Duplicate lead handling: 'refuse' (never accept), 'allow' (always accept), or 'Xd' (accept after X days)

createdAtstring required
updatedAtstring required
lastLeadAtstring nullable
appliedobject

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.

Example response

{
  "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"
}

Changes

No recorded changes to this operation across all 1 revision of this API.