Hillwinds APIDocs
Core Concepts

Filtering & Search

The API supports five ways to find data, from broad to precise.

How do I filter companies by employee count?

Filter companies by employee count with the named employee_bands filter or a numeric cf[total_number_of_employees] range. Use Filter Options to discover valid employee-band values before requesting rows.

Text search

Substring match on the entity's name field. Single-token, not multi-token fuzzy:

bash
GET /v1/companies?search=acme
search= is single-token
Multi-token queries like search=MERCER%20SAN%20FRANCISCO typically return [] — the implementation is closer to LIKE '%MERCER SAN FRANCISCO%' against the name column. Use the most distinctive token and combine with states= or other narrowing filters; for post-token disambiguation, filter the response client-side on company_city /broker_city.

Named filters

Structured filters with known values. Most accept comma-separated lists:

bash
GET /v1/companies?states=CA,NY&industries=Hospitals,Software+Publishers&employee_bands=Mid-market+Accounts

Combination logic: AND across parameters, OR within a comma-separated list. states=CA,NY&industries=Hospitals returns rows in (CA OR NY) AND Hospitals.

Unknown query parameters are rejected with 400 VALIDATION_ERROR. This catches typos early.

Column filters

Filter on any column using cf[column_name]:

Exact match:

bash
GET /v1/companies?cf[company_state]=CA,NY

# Reverse-lookup a single person by a unique field (no /personnel/lookup exists)
GET /v1/personnel?lead_type=company&cf[email_address]=jennifer.smith%40example.com
GET /v1/personnel?lead_type=company&cf[person_linkedin_url]=https%3A%2F%2Flinkedin.com%2Fin%2Fjsmith

Numeric range:

bash
GET /v1/companies?cf[total_premiums]=gte:1000000,lte:5000000
GET /v1/companies?cf[participants]=gte:100
GET /v1/companies?cf[broker_tenure_years]=lte:2

Range operators: gte: (>=), lte: (<=). Combine both for a range.

Percentage columns such as participant_growth, commission_growth, and broker_commission_growth_pct interpret numeric thresholds as percent values. For example, cf[participant_growth]=gte:1 means at least 1%, and gte:1.001 is a slightly stricter threshold than gte:1.

Validate numeric filters before a full pull
Numeric cf[] filters are applied server-side for the columns listed below. Always sanity-check a new numeric filter with &count_only=true first so you can confirm the row count before spending credits on a full response or export.

Available numeric columns:

EntityColumns
Companiesparticipants, total_premiums, medical_premiums, total_number_of_employees, broker_commission, broker_tenure_years, broker_commission_growth_pct, assets_401k, primary_broker_compensation, participant_growth
Brokerstotal_offices, total_clients, total_commissions, total_premiums
Personneltotal_number_of_employees

Named filters vs column filters — when to use which

Both syntaxes work. Pick by intent: named filters when one exists (states=, industries=, employee_bands=); reach for cf[col]= when there is no named filter, when you need a numeric range, or when you want exclude-blanks (eb[col]=true) on the same column.

Named filtersColumn filters
Examplesstates=cf[company_state]=
Validates against enums?YesYes (when column is enum-typed)
Numeric ranges?NoYes (gte:, lte:)
Match response keys 1:1?SometimesAlways — useful for round-tripping a key
Supports eb[]?NoYes

Don't mix a named filter and a cf[] filter on the same column in the same request — behavior is the AND of both, but it's easy to confuse yourself.

Signal vs column name — same name, different parameter

Three signals share names with numeric columns. They are scoped by parameter and mean different things.

NameAs signals= (signal)As cf[col]= (numeric column)
participant_growthFilter rows where YoY participant growth ≥ 20%Numeric range filter on the participant_growth field (% change)
commission_growthFilter rows where YoY commission growth ≥ 15%(Phase 2 — not yet a cf[] column)
self_fundedFilter rows flagged self-funded by the proprietary algorithmUse funding_status=Self-Funded instead

Exclude blanks

Only return rows where a column has a value:

bash
GET /v1/companies?eb[website]=true&eb[linkedin]=true

eb[column] only accepts true. Sending false returns a structured 400 VALIDATION_ERROR instead of acting as a no-op.

URL-encode values containing +
In URLs, + decodes to a space. The enum value Fifty+ relationships must be sent as Fifty%2B%20relationships. Sending it raw will be parsed as Fifty  relationships (extra space) and won't match. Bracket params and values with spaces also need encoding — cf[company_state]=CA,NY becomes cf%5Bcompany_state%5D=CA%2CNY.

Lookup (exact match, single result)

For CRM enrichment — returns one entity, 404 on no match, or 400 with suggestions on multi-match.

ResourceEndpointMatch parameters
CompanyGET /v1/companies/lookup?domain=, ?name=, or ?ein= (provide exactly one)
BrokerGET /v1/brokers/lookup?name=
bash
GET /v1/companies/lookup?domain=stripe.com
GET /v1/companies/lookup?name=Stripe+Inc
GET /v1/companies/lookup?ein=123456789
GET /v1/brokers/lookup?name=Marsh+%26+McLennan

Domains are normalized (protocol, www., trailing slash removed). For bulk lookup, use POST /v1/companies/batch (up to 100 domains/EINs) or POST /v1/personnel/batch (up to 50 company EINs).

Lookup vs cf[name]= — when to use which

lookup does three things cf[] doesn't: (1) normalizes domains, (2) returns 404 (not an empty list) when nothing matches, (3) returns 400 with suggestions when multiple entities match. Use lookup for record-matching workflows where "exact, single result" is the goal. Use cf[company_name]=...when you want a list response shape (even if it's a list of one).

Personnel is cf[]-only. There's no /personnel/lookup endpoint, so reverse-lookup by email or LinkedIn URL goes through cf[email_address]= / cf[person_linkedin_url]= on the list endpoint. See Personnel → Reverse lookup for the full recipe.

Relationship filters match history, not current

broker=, carrier=, and broker_office= match against any historical relationship the record has held — not just the primary/current. For "current Mercer clients only," filter the response client-side on primary_broker after the query. The same applies to primary_carrier and primary_broker_office.

Entity-specific filters

See each entity's reference page for its full filter list: