AI Agent Guide
The page to read first if you are an LLM, coding agent, or human author of one. Anti-pitfall guidance in one place; the autocomplete reference, recipe library, and endpoint index each have their own page.
Read this first
This page exists so you don't waste tokens re-discovering quirks the rest of us have already paid for. It is short on prose and long on tables, callouts, and copy-paste snippets. The per-resource API reference pages are the authoritative source for response shapes; this page is the authoritative source for what to avoid doing.
- This page — pitfalls + the discovery flow. Linked sub-pages for autocomplete, recipes, and the endpoint index (see below).
- /llms.txt and /llms-full.txt — the docs site flattened for context windows. Page-level
.mdURLs are not served; fetch these files or use the in-page copy button instead. - /v1/openapi.json — canonical query parameter names + types + enums for every operation. Pair with this page (which covers response shapes, dynamic filters, and the non-spec endpoints).
Base URL and auth
| Environment | Base URL | Token prefix |
|---|---|---|
| Production | https://api.hillwinds.ai/v1 | ss_live_... |
| Test keys (sandbox data; zero credits) | https://api.hillwinds.ai/v1 | ss_test_... |
curl -H "Authorization: Bearer ss_test_..." \
"https://api.hillwinds.ai/v1/companies?states=NY&employee_bands=Mid-market+Accounts&page_size=1"Expected sandbox company: Copperleaf Financial Co (EIN 737336823). A non-2xx response or empty data array means the copy-paste smoke test failed.
api.segmentstudio.com. That host does not resolve in DNS. The canonical host is api.hillwinds.ai. Substitute it anywhere you see the old domain.Endpoint cheat sheet
| Resource | List + filter | Detail | Notes |
|---|---|---|---|
| companies | GET /v1/companies | GET /v1/companies/:id | Also: /lookup, POST /batch, /export.csv, /autocomplete. |
| personnel | GET /v1/personnel | GET /v1/personnel/:id | lead_type=company|broker required. Also POST /batch, /export.csv, /autocomplete. |
| broker-offices | GET /v1/broker-offices | GET /v1/broker-offices/:id | /export.csv + /autocomplete (returns populated IDs). |
| brokers | GET /v1/brokers | GET /v1/brokers/:id | /lookup, /export.csv, /autocomplete. |
| lookalikes | POST /v1/lookalikes | Request and weight reference | One to five company, broker-office, or personnel seeds; up to 50 ranked IDs; 1 credit per result. Resolve seeds through the matching production entity endpoint first. Production keys only; test keys return PRODUCTION_KEY_REQUIRED. Custom weights affect one request and are not persisted. |
| filter-options | GET /v1/filter-options | GET /v1/filter-options/{key|resource|resource/filter} | Three drill-down shapes; all free. |
| tags | GET /v1/tags | POST /v1/tags, /tags/bulk; DELETE /v1/tags, /tags/:id | Body: {entity_id, entity_type, tag}. Aliases resource for entity_type. |
| review-flags | PATCH and DELETE are Hillwinds-internal | POST and GET /v1/review-flags | A live API key with data-flags:write can submit and list owned reviews. Only Hillwinds reviewers can approve, reject, or delete them. Alias: /v1/data-flags. |
| api-keys | GET /v1/api-keys | POST /v1/api-keys, /:id/rotate, DELETE /:id | Requires API-key account context plus keys:read/keys:write. |
| credits | GET /v1/credits | GET /v1/credits/usage | Requires API-key account context plus credits:read/usage:read. |
| reports | — | POST /v1/reports | File a bug report. Free. Use it for unexpected API behavior. |
The five universal query parameters
Every list endpoint accepts these. Internalize them and you write efficient queries by default.
| Param | Default | What it does | When to use |
|---|---|---|---|
mode | basic | basic returns ~10 fields at the cheap rate; full returns ~40-50 fields at 10x the rate. | Always start with basic; upgrade to full only when you need broker/carrier/personnel detail. |
fields | (all in tier) | Comma-separated column allowlist. id is always returned. | Use to pull only the columns you need — cheaper response, faster query. |
count_only | false | Returns total_count, no data rows. Zero credits. | Sizing a segment. ALWAYS the first call when validating a new filter. |
dry_run | false | Returns estimated_rows + estimated_credits without executing. Zero credits. | Final sanity check before a paginated pull. |
include_count | true | When false, skips per-page COUNT(*). Sets has_more via page_size+1 probe instead. | Inside a pagination loop — much faster than running COUNT each page. |
Common pitfalls
Broad queries can be expensive
Geo-only queries such as GET /v1/companies?states=CA&page_size=10 now return data. They can still represent very large segments, so pair states= with employee_bands, industries, premium_tiers, or signals when you need a targeted pull.
search= is single-token, not multi-token fuzzy
search=MERCER%20SAN%20FRANCISCO returns zero rows because the underlying implementation is a substring match against the primary name field. Try several distinctive search tokens separately and compare the results. When you know a company's website, prefer an exact domain lookup such as /v1/companies/lookup?domain=example.com.
Autocomplete has a narrow column allowlist and per-resource ID gaps
Autocomplete works the same way across all four resources but with different valid column= values, and all four return populated IDs. Full reference moved to /docs/for-ai-agents/autocomplete — short version: column= must be on the per-resource allowlist (1-2 columns only), query requires ≥2 chars, and you should prefer the resource list endpoint with ?search= when you need the full enriched record.
Personnel fields change meaning by lead_type
With lead_type=broker, company_* fields on personnel records echo the broker's own corporate entity (not a client company). With lead_type=company, they describe the contact's employer. Same field names, different meaning — read field names as "the entity context for this contact."
Validate filters before spending credits
Signal filters such as admin_change and numeric filters such as cf[total_number_of_employees] are wired through, but filter behavior can still vary by column and data freshness. Always validate with &count_only=true first. If the count is wildly different from expectation, adjust the filter before spending credits on a full pull.
seniority and job_function are allowlisted buckets
seniority=C-suite includes EAs to C-suite, Senior Directors, and many other adjacent titles. job_function accepts only allowlisted labels; unknown values now return 400 VALIDATION_ERROR with the expected values. Use Human Resources, not HR, and confirm valid labels with GET /v1/filter-options/personnel/job_function?lead_type=company or lead_type=broker.
broker= matches history, not current
broker=MERCER returns every company that has Mercer in some capacity as a broker. The primary_broker field is the broker estimated to own the relationship. Filter the returned rows on primary_broker when that is the relationship you need.
Path and body naming aliases
Tags and review flags accept both human-friendly and canonical body field names. entity_type ↔ resource; field_key ↔ field; reason ↔ issue. Responses always return the canonical name. Review-flags is also reachable at /v1/data-flags.
Deep dives
The longest sections of this guide each live on their own page — easier to land on, link to, and feed into a context window without the surrounding prose.
- Autocomplete reference — request/response shape, the per-resource
column=allowlist, which resources return populated IDs, and when to prefer the resource list endpoint with?search=instead. - Recipe library — copy-paste curl flows for the common tasks: find a company, get benefits decision-makers, build a prospect list and tag it, count for free, discover filter values, resolve a company → primary broker office ID.
- Machine-readable endpoint index — every operation the live API exposes today, in a single table for fast pattern matching.
Discovery flow — what to read in what order
- /llms.txt for the link graph.
- /v1/openapi.json for canonical query parameter names + types + enums.
- This page for pitfalls and the discovery flow.
- The endpoint index to confirm an operation exists before crafting the request.
- The per-resource API reference pages for response shapes and per-resource filter lists.
GET /v1/filter-optionslive for enum values.?count_only=true/?dry_run=truefor free probes (both 0 credits).
When the OpenAPI spec and docs disagree: spec wins for query parameter names/types/enums (the Endpoint Index is generated from it at build time); docs win for response shapes (components.schemas ships empty), dynamic filter syntax (cf[col]=, eb[col]=, gte:/lte:), headers, and credit costs.
Errors — one paragraph
Standard envelope on failure: {ok: false, error: {code, message, details[], request_id}}. Codes you'll actually hit: 400 VALIDATION_ERROR (unknown param / missing required like lead_type), 403 FORBIDDEN (basic key requesting advanced tier or missing write scope), 429 RATE_LIMITED / 429 CRAWL_DETECTED (use Retry-After), 500 INTERNAL_ERROR (retry with backoff — sometimes a 500 masks a missing scope where 403 would be more accurate; file a report if you suspect this). Full reference at /docs/errors.
When to file a report
If you hit a silent no-op filter, an unexpected 500, an obviously stale record, or an endpoint that returns the wrong shape — file a report. It feeds the next iteration of this page and reaches the API team directly. See /docs/api/reports.