Skip to content

Authentication

FirmaDB uses HTTP bearer tokens — never query parameters. Every authenticated request must include:

Authorization: Bearer fdb_live_sk_...

Key format

fdb_<env>_<class>_<kid>_<secret>_<check>
Component Values Purpose
env live or test Environment selector. Test keys hit live data but cap at 1,000 calls/day and don't bill.
class sk or rk sk = secret key (full access). rk = restricted key (scoped).
kid 12 chars, base62 Non-secret key ID — used for DB lookup, audit logs, and dashboard display.
secret 32 bytes, base62 Random secret material. ≥190 bits of entropy.
check 6 chars, base62 HMAC-SHA-256 checksum for fast format validation.

Examples:

fdb_live_sk_aB12cD34eF56_7Hk2QmRn8wXz4PvY3LjB6Tab5mDf9xKc_a1B2c3
fdb_test_rk_xY99zZ00aA11_9Kp3RsUo7yWb2QxZ1NjA8VfC4mEh6tLg_d4E5f6

Two key classes

Secret keys (sk)

  • Full access to every scope your tier permits.
  • One per account. Use for server-to-server backends.
  • Never expose them in browsers, mobile apps, or to AI agents. Use a restricted key instead.

Restricted keys (rk)

Multiple per account. Each rk is scoped, optionally constrained to specific IPs, countries, endpoints, and rate limits, and may have an expiry.

Constraint Type Description
scopes string[] Which operations the key may perform. See the scope table below.
ip_allowlist string[] IP addresses or CIDR ranges. Empty = any IP.
country_scope string[] ISO alpha-2 codes the key may access. Empty = all.
endpoints string[] Path patterns (e.g. /v1/companies/*). Empty = all permitted by scopes.
rate_limit_rpm integer Per-minute rate limit override. Lower of (this, tier default) wins.
expires_at ISO datetime / null When the key stops working. Default: 90 days for user keys, 365 for service keys.

Use restricted keys for AI agents, partner integrations, edge workers, and anywhere a leak would otherwise compromise the account.

Scopes

Scope Permits
companies:read GET /v1/companies/{country}/{registry_id}
companies:search GET /v1/companies/search
companies:enrich POST /v1/companies/lookup-batch
coverage:read GET /v1/countries, GET /v1/countries/{code}
usage:read GET /v1/account/usage

Secret keys have all scopes implicitly. Restricted keys have only the scopes explicitly granted at creation.

When a restricted key attempts an operation outside its scope, the server returns 403 insufficient_scope with required_scopes, granted_scopes, and missing_scopes arrays — so the caller knows exactly what's missing.

Anonymous access

A small set of endpoints does not require a key. They're rate-limited per IP at 60 requests/hour:

Endpoint Purpose
GET /v1/health System health and component status.
GET /v1/countries List all supported countries with record counts.
GET /v1/countries/{code} Per-country capability manifest.
GET /llms.txt Agent discovery file (unlimited, static).
GET /.well-known/agent-card.json A2A agent card (unlimited, static).
GET /openapi.yaml OpenAPI spec (unlimited, static).

Every other endpoint returns 401 unauthenticated without a valid Authorization header.

Public demo key

A read-only demo key is embedded in the docs code samples for unauthenticated visitors. It carries companies:read, companies:search, and coverage:read scopes, caps at 100 calls/day, and returns real data. Use it to try the API without signing up.

Test mode

Keys with env=test (fdb_test_*) hit the same live data but:

  • Capped at 1,000 calls/day (resets at midnight UTC).
  • Never bill. Useful for CI, integration tests, and documentation samples.
  • Same scope and constraint rules as their live counterparts.

When the daily test cap is exhausted, the API returns 429 quota_exhausted with limit.bucket = "test_daily" and limit.reset_iso pointing to the next midnight UTC.

Example 401 response

A missing or malformed key returns:

{
  "type": "https://errors.firmadb.com/unauthenticated",
  "title": "Unauthenticated",
  "status": 401,
  "detail": "Missing Authorization header. Pass your API key as 'Authorization: Bearer fdb_...'",
  "instance": "/v1/companies/FR/552120222",
  "code": "unauthenticated",
  "request_id": "req_01HZAB7MJX...",
  "retryable": false,
  "retry_after_seconds": null,
  "correction": "Add the header: Authorization: Bearer <your_api_key>",
  "suggested_request": null,
  "documentation_url": "https://errors.firmadb.com/unauthenticated"
}

Response headers include WWW-Authenticate: Bearer realm="firmadb".

Key lifecycle

  • Revocation. Revoked keys are rejected on the next request. In-flight requests authenticated before revocation complete normally.
  • Expiry. Same behavior — checked once at request start.
  • Rotation. Create a new restricted key, deploy it everywhere, then revoke the old one. There's no atomic rotation API at launch.

OAuth 2.1 (deferred)

OAuth 2.1 with PKCE and Dynamic Client Registration is on the roadmap for the hosted MCP server. Until it ships, MCP clients authenticate with restricted bearer keys (rk class). See MCP setup for how to configure this in Claude Desktop and other MCP-aware clients.