14 day free trial

Recipes

Tag and qualify companies

Tagging a company is one PATCH call. What matters is not how — it's what to tag with, and what each tag earns you downstream. Qualification (label) is the same call with three pre-baked values reserved for is this in target at all — from your side, a limited tag. The simple cases are trivial. The interesting questions show up once you treat tags as a system: anti-filters, lifecycle markers, sync state, owner routing. Here are the patterns we use.

One PATCH call sets tags or label — usually both. From the record's side it is just metadata; from your queries it is the levers that suppress noise and route work.

Mental model

Two fields, one record, one PATCH. tags are free strings you invent. label is a tag with three legal values, reserved for in-target / not-in-target / new. They sit on the same record and travel together.

Field Shape Set via Filter via
tags free strings, multi-value (CSV) PATCH /companies tags=, NOT_tags=
label enum: -1, 0, 1 PATCH /companies (same call) label=

Basics

One endpoint, one record per call. Send what you want the record to look like — both fields are optional, but at least one is needed for the call to do anything.

PATCH /v1.3/companies
Parameter Value Why
id company id Which company you are updating. Required.
tags CSV of tags Replaces the current tag set. Case-sensitive, URL-encoded.
label 1, 0 or -1 1 = in target audience · 0 = not in target audience · -1 = new / not qualified.

Response echoes the updated record. Treat it as your new source of truth — there is no second GET needed.

Common patterns

The combinations we reach for most often. Each pattern is one tag — the work is downstream, in queries that read the tag back.

Pattern Tag / label Why
Customer suppression tags=Customer Mark paying customers, then NOT_tags=Customer in every prospect query.
Competitor / churn exclusion tags=Competitor,Churned Permanent disqualification — a one-time tag that earns lifetime exclusion.
Sync state tags=Synced Tag after pushing to CRM, then NOT_tags=Synced to find what is left.
Lifecycle stage tags=Prospect | Demo | Closed-Won Track sales-pipeline state on the record itself. Pick one of a fixed set per company.
Engagement score tags=Hot | Warm | Cold Lightweight scoring without a separate field. Re-tag when the signal changes.
Owner / territory routing tags=Anna,EMEA Route records by rep or region. Filter on a tag to see your slice.
ICP qualification label=1 Mark a fit (or non-fit). FirmTrace uses the signal to bias matching toward your kind of company.

Anti-filter pattern

Most useful tags double as filters in two directions. Marking a record as Customer lets you find customers (tags=Customer); it also lets you keep them out of every other query (NOT_tags=Customer). The second use — the anti-filter — does most of the real work in production pipelines.

The shape is always the same: tag what you want to keep out, then negate it on read.

What you want Filter
Records you have not pushed to your CRM yet NOT_tags=Synced
Prospects only — no existing customers NOT_tags=Customer
Permanent exclusion list NOT_tags=Competitor,Churned,Blacklist
In-target, not-yet-customer, not-yet-synced label=1 & NOT_tags=Customer,Synced
Tag conventions earn compounding interest

Every tag you introduce becomes a future filter and anti-filter. A tag you set today is a query you do not have to write tomorrow. Cheap to add, expensive to retrofit — pick names you are willing to live with.

Considerations

Point Detail
PATCH replaces, not adds Sending tags=Customer,VIP to a company already tagged Customer,Synced loses Synced. To add: read current tags, append, write back in one call.
Tags are case-sensitive Customer ≠ customer. Pick a convention (we lean PascalCase) and document it somewhere central.
URL-encode tag values Spaces, commas inside a single tag, and any special characters need encoding before they hit the URL.
label is exclusive A company has exactly one label at a time, picked from {-1, 0, 1}. There is no multi-value form.
label is a signal back to us Tags are just yours. label=1/0 nudges FirmTrace matching toward (or away from) records that look like your in-target ones.
Invalid id → 403, not 404 A non-existent or wrong-account company id returns 403 with no records updated. Validate ids upstream.

Errors & retry

Sort responses into the usual three buckets.

Bucket Examples What to do
Transient network, 5xx, 429 Retry with exponential backoff (1s → 2s → 4s, capped). On 429, respect Retry-After if present.
Permanent 403 (invalid id), other 4xx Log and stop for that record. Retrying an invalid id will not start working — fix upstream.
Success 200 Response echoes the updated record. Persist it locally — see callout below.
Idempotency

PATCH is naturally idempotent on the same payload — two identical writes produce the same end state. The risk is the read-modify-write race: two processes that both compute a new tag set from the same starting point will overwrite each other. Serialize writes per company.id, or accept last-writer-wins.

See also Filter companies Poll for new and updated companies