> ## Documentation Index
> Fetch the complete documentation index at: https://dev.jolts.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# How to work with company lists

> Filter, paginate, investigate, and retry without duplicating work.

Use a bearer credential and an active or trialing subscription. API and MCP share the same business
logic and limits. These are supported workflows, not downloadable skill packages.

## Find candidates without returning existing customers

Send this body to `POST /api/companies/search`, or as `search_companies` arguments with a `request_key`:

```json theme={null}
{
  "query": "Companies seeking charging equipment",
  "filters": {
    "countries": ["CA", "US"],
    "kinds": ["procurement_request"],
    "exclude_domains": ["example.com"]
  },
  "limit": 10
}
```

Country filters describe the observation's country; company profiles use their supported headquarters
country. Supported kinds are `company_profile`, `procurement_request` and `facility_expansion`.
Demand classes are `explicit_request`, `proxy`,
and `structural`. `occurred_after` and `observed_after` accept ISO 8601 timestamps.

Activity search defaults `occurred_after` to 30 days ago at midnight UTC. The effective
cutoff is returned as `coverage.occurred_after`. Supply an earlier event date to widen
the window; an empty result never silently broadens it. Pagination keeps the original window.
`observed_after` is when we collected the evidence, not when the event happened.
Structural company-profile searches have no implicit event-date cutoff. An explicit `occurred_after`
excludes undated profiles; relevant company fit is not evidence of current purchasing.

## Restrict a search to known companies

Add `company_ids` or `domains` under `filters`. Exclude using `exclude_company_ids` or
`exclude_domains`. Each accepts up to 100 values. IDs are positive JSON integers; domains must be
hostnames, not URLs or email addresses. Domain matching normalizes case, surrounding whitespace,
and a trailing dot, but does not collapse subdomains or remove `www`.

Values within a field are OR; separate fields are AND. Exclusions win. An empty list does not
restrict. Domain matches require an active, currently evidenced company-domain relationship.
Unknown IDs/domains yield no matches, not invented company records. This is filtering company
evidence search, not a promise to research every supplied company or return one row per input.
Existing bounded acquisition may run for a short first page; the filters remain authoritative over
its results. Use `get_companies` for deterministic per-input lookup instead; contact enrichment is not supported.

## Continue a list

Set `target` to the desired shortlist size (1–1,000, at least `limit`), for example
`{"query":"Restaurants serving chocolate desserts","limit":20,"target":1000,"background":true}`.
This asks for supported prospects, not 1,000 rows in one response or a guarantee of coverage.
Omitting target acquires for one page and keeps the stored-data shortlist cap at 100.
`candidate_limit` reports the scan cap before relevance filtering: `max(100, 2 * target)`, or 100 when
target is omitted. The accepted shortlist is capped by an explicit target after relevance filtering.

When `next_cursor` is not null, repeat the same query, filters, limit and target with that cursor
and a **new** request key. Keep target omitted if it was omitted initially. Builder permits 25
companies per page; professional permits 50. The opaque cursor references a server-owned shortlist;
it does not carry the full result list. Pagination does not acquire more sources, replan, or rerank.
Subscription request and delivery limits still apply to every page.

`coverage.target_companies` reports the acquisition goal and `available_companies` reports the frozen
shortlist count. The latter is not a total-market count or a guarantee of current eligibility.
Without an explicit target it may exceed the page-sized acquisition goal. Evidence withdrawal can
shorten a later page. Each company has up to three supporting observations.
Older completed searches may omit `target_companies` and `available_companies` on replay. Treat
missing counts as unavailable, not zero.

## Investigate one or several companies

Call `get_companies({"ids":[123],"request_key":"review-123"})`, or
`GET /api/companies?ids[]=123` with an `Idempotency-Key` header. Supply up to twenty IDs or
domains, not both. Results include each target's found, missing or ambiguous outcome, current
supported domains, and up to three recent observations per company. No provider or AI call runs.
A completed lookup consumes one request unit and one delivered unit per distinct returned company.

`GET /api/companies/123` requires an `Idempotency-Key` and shares the same metered lookup,
with its original `company` envelope. The same key and identifier replay across all three paths.
It is not fresh research.
Legacy observation search/detail and `POST /api/usages` are deprecated. Their responses carry a
`Deprecation` header; no removal date is set. Prefer the observations and evidence nested under
company results. Use company search with `background: true` for asynchronous work and
`GET /api/usages/:id` for polling; that polling endpoint is not deprecated.

## Understand retries and usage

The same account, action, key and normalized inputs refer to one operation, even across API/MCP or
synchronous/background modes. A successful new search settles one request unit and one delivered unit
per distinct company. Fresh-evidence units count newly acquired observations actually delivered.
An identical retry or usage poll adds no charge. Polling another account's usage ID returns not found.

Reads recheck current evidence. If a delivered company loses support, replay can remove it and report
`withheld_units` without changing historical settlement. Raw provider and AI audit details are not
returned. Background operations move `pending` → `processing` → `delivered` or `failed`.

## Verify and troubleshoot

Check `companies`, supporting `evidence`, `coverage`, `usage`, and `request_allowance`, not just the
HTTP status. Similarity is not proof of buying intent. A suppressed or empty result is not proof of
absence. `invalid_cursor` means restart the search without a cursor; `idempotency_conflict` means the
key belongs to different inputs. After a terminal failure use a new key only if you intend new work.
Do not retry invalid inputs unchanged or loop on rate limits.

City/category filters, change feeds, exports, OAuth and whole-dataset downloads are not implemented.
See [MCP tools](/mcp-overview) and the API reference for exact request and response structures.
