Skip to main content
POST
/
api
/
v1
/
webhooks
/
campaigns
/
audience-filter
curl --request POST \
  --url https://chat.trysetter.com/api/v1/webhooks/campaigns/audience-filter \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "campaignId": 42,
  "sendId": 137,
  "mode": "include",
  "leads": [
    {
      "externalId": "your_lead_id_001"
    },
    {
      "externalId": "your_lead_id_002"
    }
  ]
}
'
{
  "status": "accepted",
  "leadCount": 12345
}

Documentation Index

Fetch the complete documentation index at: https://docs.trysetter.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Most campaign sends go to the full uploaded audience. This endpoint lets you narrow a specific send based on signals that aren’t known at upload time — e.g. “for tomorrow’s send, only message leads who completed step X by tonight.” POST an include or exclude list to a specific send up until 5 minutes before that send fires (the filter deadline).
Enabling on a send: in the campaign editor, toggle “Apply filter from inbound webhook” on for the target send. A send with the filter off ignores any webhook events targeting it.

Authentication

Pick the auth mode for inbound webhooks once per organization, in Settings → Webhooks:
  • API key (default) — Bearer-token auth using any active org-level API key.
  • HMAC — generate a signing key, sign the raw request body with HMAC-SHA256, send as X-Setter-Signature: sha256=<hex>. Multiple signing keys can be active concurrently for rotation.

When the filter is applied

The send’s recipient list is materialized about 60 seconds before scheduledFor. At that moment:
  1. Every lead in the campaign’s audience whose ingest status is ok is loaded.
  2. Opted-out phone numbers are dropped.
  3. The most recent filter event for that send is applied: include keeps only listed leads; exclude removes them.
  4. One row per remaining lead is inserted into the per-recipient send queue.
If you POST multiple distinct filter events before the deadline, only the latest one matters. Idempotent replays of the exact same payload return { status: "already_received" } and are no-ops.

Lead matching

A lead in your filter payload matches an audience lead if either of these is true:
  • The payload’s externalId matches the audience lead’s external_id column from the CSV (case-sensitive).
  • The payload’s phoneE164 matches the normalized E.164 stored on the audience lead.
Leads in your filter payload that don’t match any audience lead are silently ignored.

Combining with lead events

A send can have both an audience filter (this endpoint) and an event filter (matching against Send Lead Event) configured. Both must keep a recipient for them to receive the message — the filters are ANDed.

Example Usage

HMAC signature

SECRET="your-signing-secret"
BODY='{"campaignId":42,"sendId":137,"mode":"include","leads":[{"externalId":"abc123"}]}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -binary | xxd -p -c 256)

curl -X POST https://chat.trysetter.com/api/v1/webhooks/campaigns/audience-filter \
  -H "Content-Type: application/json" \
  -H "X-Setter-Signature: sha256=$SIG" \
  --data-raw "$BODY"

Bearer API key

curl -X POST https://chat.trysetter.com/api/v1/webhooks/campaigns/audience-filter \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignId": 42,
    "sendId": 137,
    "mode": "exclude",
    "leads": [
      { "phoneE164": "+15551234567" },
      { "phoneE164": "+15557654321" }
    ]
  }'

Authorizations

Authorization
string
header
required

Bearer token authentication using your API key

Body

application/json
campaignId
integer
required

Campaign that owns the targeted send.

sendId
integer
required

Send to filter. Must currently be in pending status with audienceFilterMode = webhook_filtered.

mode
enum<string>
required

include — send only to listed leads. exclude — send to everyone EXCEPT listed leads.

Available options:
include,
exclude
leads
object[]
required
Required array length: 1 - 100000 elements

Response

Filter event recorded (or duplicate of an earlier payload)

status
enum<string>

accepted on first delivery; already_received if this exact payload was already recorded for this send.

Available options:
accepted,
already_received
leadCount
integer

Count of leads in the accepted payload (omitted on already_received).