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

# Best Practices

**Never combine `query` and `filters` in the same request**

`query` and `filters` are mutually exclusive — pass one or the other, not both. If you send both, the request will not resolve to a predictable result set. If you started with a natural language `query` and want to refine it, translate the criteria into an equivalent `filters` object rather than layering `filters` on top of `query`.

```python theme={null}
# ❌ Invalid — mutually exclusive parameters combined
payload = {
    "query": "SaaS companies in the US",
    "filters": {"firmographic.company_type": ["private"]}
}

# ✅ Correct — pick one
payload = {
    "filters": {
        "location.hq.country": ["USA"],
        "business_model.offering_type": ["software"],
        "firmographic.company_type": ["private"]
    }
}
```

**Resolve industry names to codes before filtering — never pass free text to `industry.industry`**

The `industry.industry` filter expects Akta taxonomy industry codes, not free-text sector names like `"warehouse automation"` or `"fintech"`. Resolve the topic first with the [Industry Search API](/api-reference/supporting-apis/industry-search):

```python theme={null}
industry_code = requests.get(
    "https://api.akta.pro/api/v1/industry/search",
    headers={"x-api-key": API_KEY},
    params={"query": "warehouse automation"}
).json()["data"][0]["code"]

payload = {"filters": {"industry.industry": [industry_code]}}
```

If a topic maps to multiple closely related industries, pass several codes rather than relying on the single top match — `industry.industry` matches any company carrying any of the selected codes.

**Use 3-letter ISO country codes for all location filters, not country names**

`location.hq.country`, `location.market_served.markets`, and `location.offices.country` all expect 3-letter ISO 3166-1 alpha-3 codes (`USA`, `IND`, `GBR`), not full country names (`"United States"`). Passing a name instead of a code will not match. `location.hq.city` and `location.hq.region`, by contrast, take free text and region names respectively — check each field's accepted format before assuming they're interchangeable.

```python theme={null}
# ❌ Will not match
"location.hq.country": ["United States"]

# ✅ Correct
"location.hq.country": ["USA"]
```

**Understand that all filters are combined with AND logic — narrow incrementally, not all at once**

Every key inside the `filters` object must match for a company to be included in the results. Stacking many highly specific filters at once (e.g. a narrow revenue band + a narrow founding year range + a specific funding round + a specific investor) can silently return zero results if the combination doesn't exist in the data. Start with 2–3 broad filters, check `total_count`, and narrow from there rather than assembling the full filter set speculatively.

```python theme={null}
# Start broad
payload = {"filters": {"location.hq.country": ["USA"], "business_model.offering_type": ["software"]}}
# check total_count, then progressively add:
# firmographic.founded_year, financial_estimate.revenue_estimate, technology.api_detail.has_api, etc.
```

**Check `total_count` with a minimal, low-cost call before pulling a full enriched list**

A request with `limit: 1` and no `sections` costs close to nothing (enrichment sections, not row count, drive credit consumption) and immediately tells you how large a segment is via `total_count`. Use this to validate a filter combination before committing to a full enrichment pull, especially for filters you're not certain will match many companies.

```python theme={null}
size_check = requests.post(url, headers=headers, json={
    "filters": {...},
    "limit": 1
}).json()

if size_check["total_count"] == 0:
    # broaden filters before proceeding
    ...
```

**Only request the `sections` you actually need — enrichment drives credit cost, not the row count**

`credits_consumed` scales with the enrichment sections requested per company, not simply with how many companies are returned. Requesting `sections: ["firmographic", "business_model", "financial_estimate", "location", "technology", "management_profile", "funding_detail", ...]` when you only need `firmographic` and `location` unnecessarily inflates cost. Natural language queries and filter requests with no `sections` at all return identity fields only and cost 0 credits — useful for market-sizing or exploratory passes.

```python theme={null}
# Cheaper: only what you need
"sections": ["firmographic", "location"]

# More expensive: requesting everything when you only use two fields downstream
"sections": ["firmographic", "business_model", "company_assessment", "trust_signal",
             "company_hierarchy", "digital_presence", "financial_estimate", "location",
             "management_profile", "product_offering", "strategic_signal",
             "customer_profile", "industry", "technology"]
```

**Remember `funding_detail` and `mna_and_investment` are Enterprise-only**

Both the `funding_detail`/`mna_and_investment` enrichment sections and the corresponding `funding_detail.*` structured filters require an Enterprise plan. If your plan doesn't include Enterprise access, requests using these will not return the expected data — check your plan tier before building a workflow that depends on funding-stage or investor-level filtering.

**Use nested filters (like `funding_detail.funding_rounds`) for round-level conditions — don't confuse them with overview filters**

`funding_detail.funding_overview.*` filters apply to a company's aggregate funding history (total raised, most recent stage, number of rounds). `funding_detail.funding_rounds` is a nested filter whose sub-fields (`round`, `date`, `amount_usd`, `investors.uuid`, `investors.lead_investor`) apply jointly to a *single* funding round — not across the company's whole history. If you need "raised a Series B of at least \$10M led by a specific investor," use the nested `funding_detail.funding_rounds` filter, not a combination of overview filters, since overview filters can't guarantee those conditions co-occur in the same round.

```python theme={null}
# Correct: all conditions apply to the same round
"funding_detail.funding_rounds": {
    "round": ["series_b"],
    "amount_usd": {"gte": 10000000},
    "investors.lead_investor": True
}
```

**Set `sort_by` and `sort_order` explicitly for reproducible lists**

The default sort is `relevance`, which can shift between calls as the underlying index updates. For lists you'll re-run periodically (e.g. a weekly prospecting pull) or need to diff over time, sort by a stable field like `founded_year`, `total_funding`, or `revenue_estimate` with an explicit `sort_order` so the ordering — and therefore your `offset`-based pagination — stays consistent.

**Paginate with `offset` and `limit` rather than requesting the maximum every time**

`limit` maxes out at 500 per request. For segments larger than 500 companies, paginate using `offset` in increments of your `limit` rather than assuming everything fits in one call. Combine this with a stable `sort_by` (see above) so pages don't overlap or skip companies as the dataset changes between calls.

```python theme={null}
all_companies = []
offset = 0
limit = 500
while True:
    page = requests.post(url, headers=headers, json={
        "filters": filters,
        "sections": sections,
        "sort_by": "founded_year",
        "sort_order": "desc",
        "limit": limit,
        "offset": offset
    }).json()
    all_companies.extend(page["data"])
    if len(page["data"]) < limit or len(all_companies) >= page["total_count"]:
        break
    offset += limit
```

**Use `query` for exploration, `filters` for production workflows**

Natural language `query` is convenient for a first pass at an unfamiliar segment, but its interpretation can vary slightly between calls since it depends on query understanding rather than deterministic filter matching. Once you've validated that a query surfaces the right kind of companies, translate the underlying criteria into an equivalent `filters` object for any workflow you'll run repeatedly, cache, or need to audit — filters always resolve the same way given the same inputs.
