SteveSignalsDocs

Webhooks

Set up a webhook

Build an endpoint, add it under Developers, copy the signing secret, create an API key for the pages and send a test event. Includes Clay, Zapier and n8n.

This guide takes you from nothing to a verified test delivery in your own endpoint. Allow 15 minutes.

You need the admin or manager role in your organization. Other members can see webhooks but not change them.

Build an endpoint

Run a small HTTPS server that verifies the signature and answers fast.

Add the webhook

Developers → Webhooks → Add webhook.

Set filters

Pick the events, actions, competitors and projects you want. Or leave them all empty.

Copy the signing secret

Shown once. Store it as a secret in your app.

Create an API key

Your endpoint uses it to read the events, 100 per page.

Send a test event

Use Send test event from the row menu.

Check Deliveries

Confirm Delivered, status 200.

1. Build an endpoint

Your endpoint must do five things:

  1. Read the raw request body, before any JSON parsing.
  2. Verify the signature in Signals-Signature.
  3. Skip the request if you already handled its webhookId.
  4. Store the body and return 200 within 10 seconds.
  5. In a background job, read each event name's pages and store each event once, keyed by eventId. See Read a run's events.

Store the signing secret in an environment variable named SIGNALS_WEBHOOK_SECRET, and the API key in SIGNALS_API_KEY. You get them in steps 4 and 5, so start with placeholders.

Use the raw body

If your framework parses JSON first and you re-serialize it, the bytes change and the signature fails. Read the raw bytes. See Common mistakes.

Deploy the endpoint on a public HTTPS URL, for example https://your-app.com/signals-hook. Signals rejects URLs that do not meet these rules:

RuleReason
Starts with https://Plain http:// is not accepted.
Port 443Custom ports such as :8443 are rejected.
A public hostnamelocalhost, *.local and *.internal are rejected.
No IP addresshttps://203.0.113.7/… is rejected.
No wildcard DNSnip.io, sslip.io and similar are rejected.
No username or passwordhttps://user:pass@host/… is rejected.
Final URLRedirects are never followed.

To test from your laptop, use a tunnel service that gives you a public https hostname on port 443.

2. Add the webhook

Open Developers in the sidebar. The page has API keys and Webhooks.

The Developers page
Developers holds your API keys and your webhooks.

In Webhooks, click Add webhook. Enter the Endpoint URL.

The Add webhook dialog
The Add webhook dialog: URL first, then filters.

3. Set filters

Under the URL you see the filters. The dialog says: "An empty filter sends every value."

  • Events: families and sub-types. Default All events.
  • Actions: new, updated, removed. Default all three.
  • Competitors: searchable list. Default All competitors.
  • Projects: searchable list. Default All projects.

Filters combine with AND. They decide the counts in the POST and the events in the pages. You can change them later with Edit. See How webhooks work.

Click Add webhook.

4. Copy the signing secret

After you save, Signals shows the Signing secret. It starts with whsec_. The panel says: "You won't see this secret again. Store it now."

Click Copy secret, save it in your app as SIGNALS_WEBHOOK_SECRET, then click Done. If you lose it, use Rotate secret.

Treat the secret like a password. Do not commit it to git. Anyone with the secret can forge requests to your endpoint.

5. Create an API key

The POST has no events in it. Your endpoint reads them with GET /api/public/v1/events?pageToken=…, which needs an API key of the same organization.

In Developers → API keys, click Create key, name it after your endpoint, and store it as SIGNALS_API_KEY. See Create an API key.

6. Send a test event

Open the row menu (Webhook actions) and choose Send test event.

The webhook row menu
The row menu: Send test event, View deliveries, Edit, Rotate secret, Pause, Delete.

Signals queues a test run. It arrives within a minute. The test:

  • is a normal signed run webhook, in the same shape as real ones, with reviews.new at total: 1;
  • has a firstPageToken that returns one sample G2 review, so you can test your page loop too;
  • carries the header Signals-Test: true;
  • is sent only to an active webhook, and only one test can wait at a time.

Use Signals-Test to skip test deliveries in your business logic.

7. Check Deliveries

Choose View deliveries from the row menu. A successful test reads Delivered, with the status code 200, the time in ms and Attempt 1 of 9.

The Deliveries sheet
Each row is one POST to your URL: one run, with its counts, status, code and timing.

If the row is Failed or Dead, look at its error label and fix the cause. See Retries and failures.

Real runs now arrive as trackers finish their checks, one POST per run.

No-code recipes

Zapier, Clay and n8n receive the POST like any other client. Most of them cannot verify the HMAC signature, because they do not expose the raw body.

Without signature checks

Keep the URL secret (it is the only protection), filter by body keys, and rotate the URL if it leaks. Whenever you can run a few lines of code, verify the signature instead.

In each tool, the POST only tells you that a run has events. Add an HTTP step that calls GET /api/public/v1/events?pageToken=… with the x-api-key header, then loop over items. Most runs fit in one page (totalPages: 1). For more pages, repeat the HTTP step with nextPageToken until it is null.

Clay

Create a webhook table

In Clay, create a table from Webhook and copy its URL. Check that it is an https URL on the standard port.

Add it in Signals

Paste the URL into Add webhook and set filters.

Read the page

Each POST lands as one row. Add an HTTP API column that calls the page URL with the row's events token for the name you want, for example events["jobs.new"].firstPageToken. Write each item of items to its own table, and map competitor.name, signalType and metadata to columns.

Zapier

Create a Zap with Catch Hook

Trigger: Webhooks by Zapier → Catch Hook. Copy the custom webhook URL.

Add it in Signals

Paste the URL into Add webhook.

Fetch the page

Send a test event, then click Test trigger in Zapier. Add a Webhooks by Zapier → GET step on the page URL with the token and the x-api-key header. Then add a Looping by Zapier step on items to run the Zap once per event.

n8n

Add a Webhook node

HTTP method POST. Use the Production URL, not the test URL, once the workflow is active.

Respond fast

Set Respond to Immediately, so Signals gets a 200 within 10 seconds.

Page through the events

Add an HTTP Request node on the page URL with the x-api-key header, and turn on its pagination: next URL from nextPageToken, stop when it is empty. Add a Split Out node on items, then an IF node on {{ $json.signalType }}.