Skip to content

Cost Estimation

FirmaDB bills per verified result — a 2xx response that contains a real company record. Search is free, 404s are free, coverage and health calls are free. The agent's job is to estimate the real cost of a planned workflow before running it, especially when the user is paying.

What costs money — and what doesn't

Operation Cost (billable results)
Exact lookup — found 1
Exact lookup — not found (404) 0
Search — any result count 0 (search itself is always free)
Batch row — found 1 per row
Batch row — not found 0
Verify status — found 1
Verify status — not found 0
GET /v1/countries[/{code}] 0
GET /v1/account/usage 0
GET /v1/health 0

"If we can't find it, we don't charge for it."

A "verified result" requires at least name + country + registry_id + status in the response. Empty search results, well-formed-but-missing IDs, and conditional 304 Not Modified responses all cost zero.

Check current usage

GET /v1/account/usage returns your current period's quota, consumption, overage charges, and remaining balance. This is the source of truth for "how much can I still spend today?"

curl "https://api.firmadb.com/v1/account/usage" \
  -H "Authorization: Bearer $FIRMADB_API_KEY"
import httpx, os

usage = httpx.get(
    "https://api.firmadb.com/v1/account/usage",
    headers={"Authorization": f"Bearer {os.environ['FIRMADB_API_KEY']}"},
).json()
print(f"{usage['results_used']} / {usage['results_included']} used")
print(f"{usage['results_remaining']} left until {usage['period_end']}")
const usage = await fetch(
  "https://api.firmadb.com/v1/account/usage",
  { headers: { Authorization: `Bearer ${process.env.FIRMADB_API_KEY}` } }
).then(r => r.json());
console.log(`${usage.results_remaining} left until ${usage.period_end}`);

Estimate a job before running it

For agents, firmadb_estimate_cost (MCP tool) returns a min/max cost range, a quota-impact prediction, and a human_approval_recommended flag.

// firmadb_estimate_cost({"operation":"enrich","estimated_records":500,"countries":["FR","GB"]})
{
  "operation": "enrich",
  "estimated_records": 500,
  "estimated_cost": {
    "min_billable_results": 350,
    "max_billable_results": 500,
    "cost_per_result_eur": 0.005,
    "estimated_cost_eur_min": 1.75,
    "estimated_cost_eur_max": 2.50
  },
  "account_impact": {
    "tier": "solo",
    "results_remaining_before": 8766,
    "results_remaining_after_max": 8266,
    "would_exceed_quota": false
  },
  "recommendation": "Proceed. Estimated cost is within your remaining quota.",
  "human_approval_recommended": false
}
Field What it tells you
min_billable_results Lower bound — assumes some 404s
max_billable_results Upper bound — assumes 100% match rate
cost_per_result_eur Your tier's overage rate (or marginal cost within bundle)
would_exceed_quota True when max exceeds your remaining balance
human_approval_recommended True when estimated spend > €10 OR > 50% of remaining quota

Honour human_approval_recommended

When this flag is true, the agent must ask the user before executing. This is the contract that prevents an autonomous workflow from quietly burning through a month's budget. Always plan from max_billable_results, not min.

Estimate without MCP

If you're calling the REST API directly, derive the same numbers locally:

def estimate(records: int, tier: str, remaining: int) -> dict:
    rate = {"free": 0.0, "solo": 0.005, "team": 0.004, "scale": 0.003}[tier]
    max_cost = records * rate
    return {
        "max_billable_results": records,
        "estimated_cost_eur_max": round(max_cost, 2),
        "would_exceed_quota": records > remaining,
        "human_approval_recommended": max_cost > 10 or records > 0.5 * remaining,
    }

The match rate (and therefore min) depends on data quality of your inputs — assume ~70% on dirty CRM exports, ~95% on freshly registered IDs.

Pricing tiers

Tier Monthly Included Overage Best for
Free €0 1,000 (hard cap) none Evaluation, demo
Solo €29 10,000 €0.005/result Indie, single workflow
Team €99 50,000 €0.004/result Fintech, B2B sales
Scale €399 250,000 €0.003/result Platforms, high-volume
Custom from €2,000 Negotiated Negotiated Enterprise, govtech

Free is a hard cap

Free-tier accounts that exhaust 1,000 results return 429 quota_exhausted for all lookup/batch/verify calls until the next billing period. Search keeps working (it's free) — but every click-through to a record fails. The error response includes a price block with the upgrade URL. See Rate Limits.

See the full pricing page for cache windows, attribution requirements, and data licensing terms per tier.

Three patterns to avoid surprise bills

1. Always estimate before batch

1. firmadb_estimate_cost(operation="enrich", estimated_records=N)
2. if human_approval_recommended → ask user
3. otherwise → proceed

2. Cache aggressively per tier

The Solo tier's 7-day cache window means a CRM that re-enriches weekly can stay flat at ~one full batch per week instead of one per day. See Rate Limits & Caching.

3. Use If-None-Match on re-fetches

A 304 Not Modified response costs zero billable results. Send the ETag from your previous response back as If-None-Match whenever you're checking for updates rather than fetching fresh.

Account-level guard rails

For teams running autonomous agents, set a soft daily cap in your own code:

DAILY_LIMIT = 200  # billable results per day, per agent

def can_spend(needed: int) -> bool:
    spent_today = redis.get("firmadb:spend:today") or 0
    return int(spent_today) + needed <= DAILY_LIMIT

Combine with firmadb_estimate_cost for a belt-and-braces guard that protects your budget even if the agent's prompt drifts.

What's next