Signals

Create Public Tenders Watchlist signal

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.

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

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

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.

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.

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.

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.

post/api/v1/signals/public-tenders-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/public-tenders-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": [
      "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"
}

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.