Reading the catalog, previewing a preset, and reading your signals and the imports feed requires the
signals:read scope. Creating, editing, duplicating, pausing, resuming, archiving, and unarchiving requires signals:write.Before you start
1
Create an API key
In the Topo dashboard, go to Settings → Developers → API keys, click Create Key, and grant
signals:read, signals:write, or both. The raw key is shown once — see Authentication.2
Pick a preset
A signal is always built from a catalog preset, which decides what gets detected and which detection filters you may send. See Browse the catalog.
3
Preview, then create
When the preset’s
preview_supported is true, send your filters to POST /v1/signals/preview and check the sample before you create the signal. See Preview a signal.Browse the catalog
GET /v1/signals/presets returns every preset you can create a signal from. Presets that are announced but not open for creation yet are omitted, so anything in this response is safe to pass as signal_type.
The catalog covers LinkedIn engagement and keyword mentions, hiring, job-description keywords, funding, technology adoption, news, and your own first-party events (
CUSTOM_EVENT, fed by the Events API).
Preview a signal before creating it
POST /v1/signals/preview samples what a preset would detect with a given set of detection filters, without creating anything. Use it to check that your search_filters catch the right companies or people before you commit to a signal. It takes the same signal_type and search_filters as POST /v1/signals, and only needs signals:read.
total_count is how many facts the provider reports over that window, or null when the provider does not count. Company-scope presets fill the company fields; people-scope presets fill the person fields.
A preset whose preview_supported is false returns 422.
Create a signal
POST /v1/signals provisions the whole thing in one call: the detection search, the destination list, and the import rules. The signal starts ACTIVE and runs a first check immediately instead of waiting for its daily slot.
201 Created with the signal:
url opens the signal in the Topo dashboard and list_url opens its destination list, so you can link from your own tools straight to what a signal collected.
Request fields
string
required
The catalog preset to build. Must be one of the
signal_type values from GET /v1/signals/presets; a preset that is not open for creation returns 404.string
required
Name of the signal and of the destination list Topo creates for it. Leading and trailing whitespace is trimmed, and a name that is empty after trimming is rejected.
object
Detection filters, as an object of filter key to a list of plain strings —
{"job_title_or": ["VP Sales"]}. Only keys in the preset’s filter_keys are accepted, and every key in required_filter_keys must be present with a non-empty value.string
PEOPLE or COMPANIES. Leave it out to follow the preset’s own scope. A COMPANY-scope preset may set PEOPLE to import the people behind the companies it detects; a PEOPLE-scope preset cannot import companies unless its scope_selectable_at_creation is true.string
What your own events identify —
PEOPLE for email or LinkedIn subjects, COMPANIES for domains. Required for the custom-event preset and rejected for every other preset.object
Filters narrowing who or what is imported once a fact is detected — personas for a
PEOPLE target, firmographics for a COMPANIES target. Same shape as search_filters.string (uuid)
Sequence template that imported leads are enrolled into. People destinations only. A template from another workspace returns
404.boolean
default:"true"
Whether imported leads get their email enriched.
boolean
default:"true"
Whether imported leads get their phone enriched.
integer
Daily ceiling on imported entries. Must be at least 1 and within your organization’s lead limit. Cannot be combined with
max_companies_per_run.integer
Daily ceiling on detected companies consumed. Only valid on a company signal importing people.
integer
How many people to import per detected company. Requires
max_companies_per_run.How the daily ceiling is resolved
max_per_day on the response is the number Topo actually enforces:
Signal status
POST /v1/signals/{signal_id}/pause, /resume, /archive, and /unarchive returns the updated signal with its new status.
- Resume makes the signal due right away, so the next check runs without waiting for the daily slot.
- Archive retires the signal. Resuming or re-archiving an archived signal returns
409. - Unarchive restores an archived signal as
PAUSED, with its filters, destination list, and imported entries intact. Resume it when you want it checking again. Unarchiving a signal that is not archived returns409.
Prefer pausing when a signal should only stop for now. There is no delete in
/v1 — archiving preserves the provenance linking every imported entry to the event that produced it, and unarchiving brings the signal back whenever you need it.Edit a signal
PATCH /v1/signals/{signal_id} is a partial update: fields you leave out keep their current value, and the response is the full signal detail after the change. Renaming also renames the destination list.
name, search_filters, import_search_filters, the caps (max_per_run, max_companies_per_run, max_contacts_per_company), enrich_email, enrich_phones, and sequence_template_id. Sending a filters object replaces the current filters for that key set, so send the complete set you want, not just the changed keys. Send null for a cap or sequence_template_id to clear it.
The
signal_type and import_target are fixed once the signal exists — to change what kind of thing a signal watches, or whether it imports people or companies, duplicate it with the new configuration and archive the original. An archived signal can only be renamed; any other edit returns 422 until you unarchive it. The same 422 rules as creation apply: unknown filter keys, missing required filters, or contradictory caps are rejected and the signal is left unchanged.
Duplicate a signal
POST /v1/signals/{signal_id}/duplicate copies a signal — same preset, detection filters, import filters, caps, enrichment, and sequence template — onto a new destination list. The copy starts ACTIVE and runs a first check immediately; the original is left as it was. Use it to fan a working configuration out across regions or personas, or as the first step of changing something PATCH cannot.
string
Name of the copy and of the destination list created for it. Leave it out to get the source name followed by
(Copy).201 Created with the new signal, in the same shape as POST /v1/signals. Duplicating an archived signal works: the copy is active even though the source is not.
List and read signals
GET /v1/signals returns the workspace’s signals, most recently created first, in the standard pagination envelope. Archived signals are hidden unless you ask for them with include_archived=true.
GET /v1/signals/{signal_id} returns the same fields plus the signal’s full configuration: search_filters, import_search_filters, sequence_template_id, import_target, and event_subject. The filters come back in exactly the shape POST /v1/signals and PATCH /v1/signals/{signal_id} accept, so you can read one signal, tweak it, and send it back without translation.
404, never 403.
Read the imports feed
GET /v1/signals/imports is the audit trail of every signal in the workspace: which signal fired, who or which company it was about, and what Topo did with it. Entries are ordered by when the underlying fact occurred, most recent first.
Import status
Filters
kind tells you which half of the entry is filled in: a CONTACT entry carries the person fields (first_name, email, company_domain), an ACCOUNT entry carries account_name and account_domain. contact_id and account_id are populated once the record exists in your workspace.
Errors
See Errors & Limits for the full error envelope and the
X-RateLimit-* headers.
Example configuration error (422)