Signals

Create Job Offers signal

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.

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, 1 when omitted — personaLocations, personaExcludedLocations, personaLocationsOnly — default false; true makes personaLocations alone decide where contacts are (empty = anywhere) while locations only targets the job; false keeps contacts within locations too — 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 — requireContact — default false; true = only leads with a contact are delivered: a company where nobody matching your personas is found is neither delivered nor charged, and this wins over companyOnlyWhenContactsRefused). Plus dailyLeadLimit (1–999,999, default 100) and initial status (draft | active | paused, default draft).

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.

Use cases:

  • Hiring = budget — a company hiring for a function is investing in it; pitch the enabling tool for that team.
  • Role-based targeting — a 'Head of X' opening → pitch X solutions to that department.
  • Pre-arrival outreach — reach the hiring manager before the new hire starts.
post/api/v1/signals/job-offers

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/job-offers
  • 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

duplicateHandlingstring nullable

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.

statusstring nullable

Initial status (default: draft). Accepts draft, active, or paused. If active, mandatory config fields are validated.

Example request

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

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.