---
title: "A signal is waiting on you"
method: POST
path: "signal.action_required"
tags: ["Signals"]
---

# A signal is waiting on you

`POST signal.action_required` (webhook)

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.

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

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

**Use cases:**
- Approve automatically under your own budget: call `apiEndpoint` when `quote.estimatedCost` (or `quote.credits`) is below your threshold.
- Route the decision to a person: post `message` and `confirmUrl` to the account owner's Slack or ticket queue.
- 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.

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

## Payload

- object: Sent to the signal's `webhookUrl` when the signal starts waiting on you.
  - `event` string, required: Always `signal.action_required`.
  - `eventId` string, required: Unique id of this ask. Also sent as the `X-Webhook-Id` header; use it to ignore a duplicate delivery.
  - `signalId` string, required: The signal waiting on you.
  - `signalName` string, required: Its name.
  - `signalTypeId` string, required: Its type, e.g. `new_decision_maker_watchlist`.
  - `code` string, required: 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`.
  - `createdAt` string, required: When the event was sent, ISO 8601 UTC.
  - `message` string, required: The same plain-language explanation as the signal's warning.
  - `quote` object, required: 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`.
  - `confirmUrl` string, required: The dashboard page that shows the quote with its confirm button.
  - `apiEndpoint` object, required: The call that unblocks the signal.
    - `method` string, required: HTTP method, `POST`.
    - `url` string, required: Full URL of the call, with your signal id in it.
    - `body` object, nullable: JSON body to send, or `null` when the call takes none.

## Acknowledgement `200`

Any 2xx acknowledges the event. Other answers are recorded in your webhook deliveries; they never pause lead delivery.

---

[API](https://skmtc.dev/rodz/apis/rodz-api.md) · [All operations](https://skmtc.dev/rodz/apis/rodz-api/llms.txt) · [OpenAPI document](https://skmtc.dev/rodz/apis/rodz-api/revisions/3003505ff896?raw)
