Agent docs

Docs your agent can read.

Plain Markdown for Claude, Cursor or any LLM agent. llms.txt is the index, llms-full.txt holds every function, credit cost, rate limit, error and the MCP setup in one file, and each function also has its own .md file. The raw schema is at /openapi.json and agents can call the API directly through /mcp. Costs and examples are generated from the live API, so they match what is billed.

Files and endpoints

Paste this into your agent

Read https://tools.epsimo.org/llms.txt, then fetch the per-function Markdown you need. Send the key in the x-token header ($API_KEY). Call GET /usage before bulk runs, wait for Retry-After on 429 and treat inferred emails as unverified.

llms-full.txt

The full reference, as served at /llms-full.txt.

# API Bridge (tools.epsimo.org): reference for AI agents

> API Bridge is a credit-metered REST API (and MCP server) for B2B company data: website qualification, one-call enrichment, professional email discovery, page text, questions about a website and search in the official French company registry. Generated from the live OpenAPI document and cost table.

## Quick start

1. Get a free API key at https://tools.epsimo.org/#signup (100 free credits per month).
2. Call `GET /usage` to check the balance.
3. Send JSON with the key in the `x-token` header:

```bash
curl -X POST https://tools.epsimo.org/qualify \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://acme.fr"}'
```

## Authentication

- Send the key in the `x-token` header on every REST call. The MCP endpoint also accepts `Authorization: Bearer <API key>`.
- Keys look like `ab_live_...`; create one at https://tools.epsimo.org/#signup.
- Never put the key in a URL or a query string.
- A key must have accepted the current terms of service (https://tools.epsimo.org/legal/terms), otherwise metered calls return 403.

## Credits and pricing

Cost per successful call (failed calls are not billed):

- `qualify` (POST /qualify): 4 credits, 1 credit when served from the 7-day cache
- `enrich` (POST /enrich): 8 credits, 3 credits when served from the 7-day cache
- `question` (POST /question): 3 credits
- `scrape` (POST /scrape): 2 credits
- `email-verify` (POST /email-verify): 2 credits
- `entreprise` (POST /entreprise): 1 credit
- `entreprise-geo` (POST /entreprise/geo): 1 credit
- `usage` (GET /usage): Free
- `health` (GET /health): Free

Free credits: 100 per month (free plan).

Credit packs (one-time purchase, no subscription):

- 1,000 credits: 40 EUR
- 5,000 credits: 200 EUR
- 10,000 credits: 400 EUR

Price per credit: 0.04 EUR (cheapest pack).

Buy at https://tools.epsimo.org/#pricing (Stripe checkout). Purchased credits are used after the free ones.

Monthly quota (credits a key can spend per UTC month):

- free: 10,000 credits
- pro: 100,000 credits

## Rate limits

- free keys: 60 requests per minute
- pro keys: 300 requests per minute
- Anonymous calls and public pages: 30 requests per minute per IP.
- Over the limit: HTTP 429 `Rate limit exceeded` with `Retry-After: 60`.
- Monthly quota reached: HTTP 429 `Monthly quota reached`, `Retry-After` = seconds until the next UTC month.

## Errors

HTTP errors have the body `{"status": <int>, "error_message": "<text>"}`.

- 402: `Insufficient credits: route costs N, available M. Buy credits via POST /billing/checkout`.
- 403: `Invalid or missing token` (no or unknown key), `Forbidden for this key`, or `Terms of service not accepted. See /legal/terms and POST /legal/terms/accept`.
- 422: request validation failed (FastAPI `detail` list).
- 429: rate limit or monthly quota (see above); wait `Retry-After` seconds.
- 502: the French company registry could not be reached (`/entreprise*`); other registry HTTP errors are passed through as `Entreprise API error: ...`. Not billed.
- 503: the French company registry is busy (upstream rate limit), with `Retry-After`; not billed. `Service temporarily unavailable` when a dependency fails.

Business failures of `/qualify`, `/question`, `/scrape` and `/enrich` come back as HTTP 200 with a `status` field in the body other than 200 (for example 400 for an invalid URL, 422 when the site cannot be read, 502 when `/enrich` found nothing). `/email-verify` uses a string `status` (`valid`, `not_found`, `suppressed`, `error`). Only successful outcomes are billed.

## Caching

- `/qualify` and the company sections of `/enrich` are cached 7 days per normalised URL. A hit has `cached: true` and costs the cached price; `refresh: true` recomputes at full cost.
- French registry responses (`/entreprise`, `/entreprise/geo`, the registry section of `/enrich`) are cached 60 minutes.

## Data provenance and limitations

- French registry: API Recherche d'Entreprises (DINUM), Licence Ouverte 2.0.
- Qualification, answers and summaries are generated by a language model from the website text: estimates, not facts.
- Emails are inferred from published address patterns and MX/SPF/DMARC checks; mailboxes are never probed. Opted-out domains and persons are never returned.
- Personal email addresses found in page text are redacted.
- `departement`, `code_postal`, `code_commune`, `region` and `epci` filter on establishments (offices), not on the head office: a result's `siege` (HQ) can be in another place. The offices that matched are in `matching_etablissements`; read them before telling a user where a company is located.

## Do not

- Do not present inferred email addresses as verified: they are pattern-based and the mailbox is never probed.
- Do not loop on 429: wait the number of seconds in `Retry-After`, then retry once.
- Do not start a bulk run without calling `GET /usage` first to check the balance and the monthly quota.
- Do not send fields that are not in the request tables: unknown fields are ignored, so a misspelled filter silently returns unfiltered results (invalid values get 422).
- Do not put the API key in a URL or a query string, and do not log or echo it.
- Do not treat a `siege` (head office) address as the place that matched an establishment filter: use `matching_etablissements`.

## MCP

The API is also an MCP server (Streamable HTTP, JSON-RPC 2.0) at `https://tools.epsimo.org/mcp`, with one tool per endpoint, billed in the same credits. `initialize` and `tools/list` are public; every `tools/call` needs the key (`x-token: <API key>` or `Authorization: Bearer <API key>`) and runs the REST route with the same auth, rate limits, credits and response body.

Tools: `qualify_company`, `enrich_company`, `find_email`, `search_french_companies`, `search_companies_near`, `scrape_page`, `ask_website`, `get_usage`.

Claude Code:

```bash
claude mcp add --transport http api-bridge https://tools.epsimo.org/mcp --header "x-token: $API_KEY"
```

Claude Desktop only speaks stdio: bridge the HTTP endpoint with `mcp-remote` in `claude_desktop_config.json` (replace `ab_live_...` with your key):

```json
{
  "mcpServers": {
    "api-bridge": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://tools.epsimo.org/mcp",
        "--header",
        "x-token:${API_KEY}"
      ],
      "env": {
        "API_KEY": "ab_live_..."
      }
    }
  }
}
```

Cursor (`.cursor/mcp.json`) or any client that speaks HTTP (replace `ab_live_...` with your key):

```json
{
  "mcpServers": {
    "api-bridge": {
      "type": "http",
      "url": "https://tools.epsimo.org/mcp",
      "headers": {
        "x-token": "ab_live_..."
      }
    }
  }
}
```

## Functions

| Function id | Endpoint | Cost | Standalone file |
| --- | --- | --- | --- |
| `qualify` | `POST /qualify` | 4 credits, 1 cached | https://tools.epsimo.org/docs/qualify.md |
| `enrich` | `POST /enrich` | 8 credits, 3 cached | https://tools.epsimo.org/docs/enrich.md |
| `question` | `POST /question` | 3 credits | https://tools.epsimo.org/docs/question.md |
| `scrape` | `POST /scrape` | 2 credits | https://tools.epsimo.org/docs/scrape.md |
| `email-verify` | `POST /email-verify` | 2 credits | https://tools.epsimo.org/docs/email-verify.md |
| `entreprise` | `POST /entreprise` | 1 credit | https://tools.epsimo.org/docs/entreprise.md |
| `entreprise-geo` | `POST /entreprise/geo` | 1 credit | https://tools.epsimo.org/docs/entreprise-geo.md |
| `usage` | `GET /usage` | free | https://tools.epsimo.org/docs/usage.md |
| `health` | `GET /health` | free | https://tools.epsimo.org/docs/health.md |

## Company qualification (POST /qualify)

Function id: `qualify`. Standalone file: https://tools.epsimo.org/docs/qualify.md

### Purpose

Industry, target audience, market and a value proposition from any company website.

### When to use

- You need the industry, target audience, market (B2B/B2C) and a one-sentence value proposition of a company from its website.

### Do not use when

- You also need the registry record or the email domain: call `enrich` once instead of several functions.
- You need raw page text (use `scrape`) or a free-form answer (use `question`).

### Endpoint

- Method and URL: `POST https://tools.epsimo.org/qualify`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: 4 credits, 1 credit when served from the 7-day cache

### Request fields

| Name | Type | Required | Default | Constraints | Description |
| --- | --- | --- | --- | --- | --- |
| `url` | string | yes | - | - | The company website URL to scrape and qualify. |
| `refresh` | boolean | no | `false` | - | Bypass the 7-day result cache and recompute (full cost). |

### Example request

```bash
curl -X POST https://tools.epsimo.org/qualify \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://acme.fr"}'
```

Request body:

```json
{
  "url": "https://acme.fr"
}
```

### Example response

```json
{
  "value_proposition": "ACME builds cloud invoicing software for small businesses.",
  "industry": "Software",
  "target_audience": "business owners",
  "market": "B2B",
  "status": 200,
  "error_message": null
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- Results are cached 7 days per normalised URL; a cache hit has `cached: true` and costs the cached price. `refresh: true` recomputes at full cost.
- HTTP 200 with a body `status` other than 200 (for example 422 when the site could not be read, 400 for an invalid URL) is a failure and is not billed.
- The classification is generated by a language model from the site text: treat it as an estimate.

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 422: Request validation failed (a field is missing, mistyped or out of range)
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `qualify_company` on `https://tools.epsimo.org/mcp`.
Arguments: `url` (required), `refresh`.

## One-call enrichment (POST /enrich)

Function id: `enrich`. Standalone file: https://tools.epsimo.org/docs/enrich.md

### Purpose

Registry record, qualification and a professional email in a single request.

### When to use

- You need several facts about one company in a single call: French registry record, qualification, email domain and, with `first_name` + `last_name`, the likely contact email.

### Do not use when

- You only need one section: the dedicated function is cheaper.
- The company is not French and you only need the registry part.

### Endpoint

- Method and URL: `POST https://tools.epsimo.org/enrich`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: 8 credits, 3 credits when served from the 7-day cache

### Request fields

| Name | Type | Required | Default | Constraints | Description |
| --- | --- | --- | --- | --- | --- |
| `url` | string | yes | - | - | The company website URL. |
| `first_name` | string or null | no | - | - | Contact first name (with last_name, enables the contact section). |
| `last_name` | string or null | no | - | - | Contact last name (with first_name, enables the contact section). |
| `siren` | string or null | no | - | pattern `^\d{9}$` | 9-digit SIREN; exact registry match when given. |
| `company_name` | string or null | no | - | - | Company name for the registry search (default: derived from the URL). |
| `refresh` | boolean | no | `false` | - | Bypass the 7-day result cache and recompute (full cost). |

### Example request

```bash
curl -X POST https://tools.epsimo.org/enrich \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://acme.fr","first_name":"Jean","last_name":"Dupont"}'
```

Request body:

```json
{
  "url": "https://acme.fr",
  "first_name": "Jean",
  "last_name": "Dupont"
}
```

### Example response

```json
{
  "url": "https://acme.fr",
  "registry": {"nom_complet": "ACME", "siren": "123456789", "...": "..."},
  "qualification": {"industry": "Software", "market": "B2B", "...": "..."},
  "email_domain": {"domain": "acme.fr", "provider": "OVHcloud", "...": "..."},
  "contact": {"email": "jean.dupont@acme.fr", "confidence": "high", "...": "..."},
  "errors": {},
  "cached": false,
  "source": {"registry": "API Recherche d'Entreprises (DINUM), Licence Ouverte 2.0"},
  "status": 200,
  "error_message": null
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- Sections fail independently: a failed section is null and explained in `errors`, the rest is still usable.
- `status: 502` in the body means neither the registry nor the qualification was found; that call is not billed.
- Company-level sections are cached 7 days (`cached: true`, cached price); `refresh: true` recomputes at full cost.
- `siren` (9 digits) gives an exact registry match; otherwise the registry is searched by `company_name` or the domain name.
- The contact email is pattern-inferred, never probed (see `email-verify`).
- Registry data source: API Recherche d'Entreprises (DINUM), Licence Ouverte 2.0.

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 422: Request validation failed (a field is missing, mistyped or out of range)
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `enrich_company` on `https://tools.epsimo.org/mcp`.
Arguments: `url` (required), `siren`, `company_name`, `first_name`, `last_name`, `refresh`.

## Ask the site (POST /question)

Function id: `question`. Standalone file: https://tools.epsimo.org/docs/question.md

### Purpose

A short, grounded answer about a company website, without reading it yourself.

### When to use

- You need a short answer about a company that is stated on its website (offer, pricing, positioning, customers).

### Do not use when

- The answer is not likely to be on the page: the model answers from the page text only.
- You need structured fields (use `qualify`).

### Endpoint

- Method and URL: `POST https://tools.epsimo.org/question`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: 3 credits

### Request fields

| Name | Type | Required | Default | Constraints | Description |
| --- | --- | --- | --- | --- | --- |
| `url` | string | yes | - | - | - |
| `question` | string | yes | - | - | - |

### Example request

```bash
curl -X POST https://tools.epsimo.org/question \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://acme.fr","question":"What does the company sell?"}'
```

Request body:

```json
{
  "url": "https://acme.fr",
  "question": "What does the company sell?"
}
```

### Example response

```json
{
  "answer": "ACME sells cloud invoicing software to small businesses.",
  "status": 200,
  "error_message": null
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- HTTP 200 with a body `status` other than 200 (422 when the page could not be read or answered) is a failure and is not billed.
- Personal email addresses in the answer are redacted.

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 422: Request validation failed (a field is missing, mistyped or out of range)
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `ask_website` on `https://tools.epsimo.org/mcp`.
Arguments: `url` (required), `question` (required).

## Page extraction (POST /scrape)

Function id: `scrape`. Standalone file: https://tools.epsimo.org/docs/scrape.md

### Purpose

The main text of any page, direct fetch with a headless-browser fallback.

### When to use

- You need the readable text of one page to process it yourself.

### Do not use when

- You only need a summary or a classification (use `qualify` or `question`).

### Endpoint

- Method and URL: `POST https://tools.epsimo.org/scrape`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: 2 credits

### Request fields

| Name | Type | Required | Default | Constraints | Description |
| --- | --- | --- | --- | --- | --- |
| `url` | string | yes | - | - | The company website URL to scrape and qualify. |

### Example request

```bash
curl -X POST https://tools.epsimo.org/scrape \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://acme.fr"}'
```

Request body:

```json
{
  "url": "https://acme.fr"
}
```

### Example response

```json
{
  "text": "ACME builds cloud invoicing software for small businesses...",
  "length": 743,
  "method": "direct",
  "elapsed_s": 0.8,
  "status": 200,
  "error_message": null
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- Direct fetch first, headless-browser fallback when needed; `method` says which one was used.
- Personal email addresses in the text are redacted.
- HTTP 200 with a body `status` other than 200 is a failure and is not billed.

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 422: Request validation failed (a field is missing, mistyped or out of range)
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `scrape_page` on `https://tools.epsimo.org/mcp`.
Arguments: `url` (required).

## Email discovery (POST /email-verify)

Function id: `email-verify`. Standalone file: https://tools.epsimo.org/docs/email-verify.md

### Purpose

The most likely professional address, inferred from published patterns — never probed.

### When to use

- You need the most likely professional email of a named person at a company whose website you know.

### Do not use when

- You need a verified, deliverable address: the result is pattern-inferred (`verification: "pattern_inferred"`) and the mailbox is never probed (no SMTP).
- You do not have both the first and the last name.

### Endpoint

- Method and URL: `POST https://tools.epsimo.org/email-verify`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: 2 credits

### Request fields

| Name | Type | Required | Default | Constraints | Description |
| --- | --- | --- | --- | --- | --- |
| `url` | string | yes | - | - | The company website URL (used to derive the email domain). |
| `first_name` | string | yes | - | - | First name of the contact. |
| `last_name` | string | yes | - | - | Last name of the contact. |

### Example request

```bash
curl -X POST https://tools.epsimo.org/email-verify \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://acme.fr","first_name":"Jean","last_name":"Dupont"}'
```

Request body:

```json
{
  "url": "https://acme.fr",
  "first_name": "Jean",
  "last_name": "Dupont"
}
```

### Example response

```json
{
  "domain_used": "acme.fr",
  "email": "jean.dupont@acme.fr",
  "confidence": "high",
  "pattern": "{f}.{l}",
  "verification": "pattern_inferred",
  "candidates": [
    {"email": "jean.dupont@acme.fr", "pattern": "{f}.{l}", "score": 0.908},
    {"email": "jdupont@acme.fr", "pattern": "{fi}{l}", "score": 0.027}
  ],
  "domain_checks": {"mx": ["mx1.mail.ovh.net"], "provider": "OVHcloud",
                    "spf": true, "dmarc": true, "disposable": false},
  "generic_emails": ["contact@acme.fr"],
  "cached": false,
  "status": "valid"
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- `confidence` (high / medium / low) and the ranked `candidates` tell how sure the pattern is; present the address as a guess, not a fact.
- Only `status: "valid"` is billed; `not_found`, `error` and `suppressed` are free.
- The suppression list is respected: an opted-out domain or person returns `email: null` and `status: "suppressed"`.

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 422: Request validation failed (a field is missing, mistyped or out of range)
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `find_email` on `https://tools.epsimo.org/mcp`.
Arguments: `url` (required), `first_name` (required), `last_name` (required).

## French company search (POST /entreprise)

Function id: `entreprise`. Standalone file: https://tools.epsimo.org/docs/entreprise.md

### Purpose

10M+ companies: name, activity, size, headcount, revenue and directors.

### When to use

- You need French companies matching a name, activity code (NAF/APE), size, headcount, revenue, location or director name.

### Do not use when

- You search around GPS coordinates (use `entreprise-geo`).
- The company is not registered in France.

### Endpoint

- Method and URL: `POST https://tools.epsimo.org/entreprise`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: 1 credit

### Request fields

| Name | Type | Required | Default | Constraints | Description |
| --- | --- | --- | --- | --- | --- |
| `q` | string or null | no | - | - | Search terms: company name, address, directors, or elected officials. |
| `departement` | string or null | no | - | - | Department code(s), 2-3 digits, comma-separated. Filters on establishments. |
| `per_page` | integer | no | `10` | >= 1; <= 25 | Number of results per page (max 25). |
| `activite_principale` | string or null | no | - | - | NAF/APE activity code(s), comma-separated. Applies to the legal unit only. |
| `section_activite_principale` | string or null | no | - | - | Activity section letter(s), comma-separated. A=Agriculture, B=Extractive, C=Manufacturing, D=Energy, E=Water, F=Construction, G=Commerce, H=Transport, I=Hospitality, J=IT, K=Finance, L=Real estate, M=Scientific, N=Admin support, O=Public admin, P=Education, Q=Health, R=Arts, S=Other services, T=Households, U=Extra-territorial. |
| `categorie_entreprise` | string or null | no | - | - | Company size category: PME, ETI, or GE. Comma-separated. |
| `nature_juridique` | string or null | no | - | - | Legal category code(s) of the legal unit, comma-separated. |
| `tranche_effectif_salarie` | string or null | no | - | - | Employee headcount bracket code(s), comma-separated. |
| `etat_administratif` | string or null | no | - | - | Administrative status: 'A' = Active, 'C' = Ceased. |
| `code_postal` | string or null | no | - | - | Postal code(s), 5 digits, comma-separated. Filters on establishments. |
| `code_commune` | string or null | no | - | - | INSEE commune code(s), 5 chars, comma-separated. Filters on establishments. |
| `region` | string or null | no | - | - | Region code(s), 2 digits, comma-separated. Filters on establishments. |
| `epci` | string or null | no | - | - | EPCI SIREN number(s), comma-separated. Filters on establishments. |
| `code_collectivite_territoriale` | string or null | no | - | - | Territorial collectivity code (Commune=INSEE code, EPCI=SIREN, Département=INSEE+'D', Région=INSEE). |
| `nom_personne` | string or null | no | - | - | Last name of a stakeholder (director or elected official). |
| `prenoms_personne` | string or null | no | - | - | First name(s) of a stakeholder (director or elected official). |
| `date_naissance_personne_min` | string or null | no | - | - | Minimum birth date of a stakeholder (YYYY-MM-DD). |
| `date_naissance_personne_max` | string or null | no | - | - | Maximum birth date of a stakeholder (YYYY-MM-DD). |
| `type_personne` | string or null | no | - | - | Stakeholder type: 'dirigeant' (director) or 'elu' (elected official). |
| `ca_min` | integer or null | no | - | - | Minimum revenue (chiffre d'affaires) in euros. |
| `ca_max` | integer or null | no | - | - | Maximum revenue (chiffre d'affaires) in euros. |
| `resultat_net_min` | integer or null | no | - | - | Minimum net income (résultat net) in euros. |
| `resultat_net_max` | integer or null | no | - | - | Maximum net income (résultat net) in euros. |
| `id_convention_collective` | string or null | no | - | - | Collective agreement identifier (IDCC) of an establishment. |
| `id_finess` | string or null | no | - | - | FINESS geographic identifier of an establishment (9 digits). |
| `id_rge` | string or null | no | - | - | RGE (Reconnu Garant de l'Environnement) identifier of an establishment. |
| `id_uai` | string or null | no | - | - | UAI (Unité Administrative Immatriculée) identifier of an establishment. |
| `convention_collective_renseignee` | boolean or null | no | - | - | Only companies with at least one establishment with a declared collective agreement. |
| `egapro_renseignee` | boolean or null | no | - | - | Only companies with a professional gender equality index (Egapro). |
| `est_achats_responsables` | boolean or null | no | - | - | Only companies with the RFAR (Relations Fournisseurs et Achats Responsables) label. |
| `est_alim_confiance` | boolean or null | no | - | - | Only companies with at least one Alim'Confiance sanitary control result. |
| `est_association` | boolean or null | no | - | - | Only associations (RNA identifier or association legal category). |
| `est_bio` | boolean or null | no | - | - | Only companies with at least one establishment certified organic (Agence Bio). |
| `est_collectivite_territoriale` | boolean or null | no | - | - | Only territorial collectivities. |
| `est_entrepreneur_individuel` | boolean or null | no | - | - | Only sole proprietorships (entreprises individuelles). |
| `est_entrepreneur_spectacle` | boolean or null | no | - | - | Only companies with a performing arts entrepreneur license. |
| `est_ess` | boolean or null | no | - | - | Only social and solidarity economy (ESS) companies. |
| `est_finess` | boolean or null | no | - | - | Only companies in the health/social sector (FINESS). |
| `est_organisme_formation` | boolean or null | no | - | - | Only companies with a training organization establishment. |
| `est_patrimoine_vivant` | boolean or null | no | - | - | Only companies with the Entreprise du Patrimoine Vivant (EPV) label. |
| `est_qualiopi` | boolean or null | no | - | - | Only companies with Qualiopi certification. |
| `est_rge` | boolean or null | no | - | - | Only companies recognized as Garant de l'Environnement (RGE). |
| `est_siae` | boolean or null | no | - | - | Only work integration social enterprises (SIAE). |
| `est_service_public` | boolean or null | no | - | - | Only public service organizations. Note: not exhaustive, may contain false positives. |
| `est_l100_3` | boolean or null | no | - | - | Only administrations per article L.100-3 CRPA. Note: not exhaustive, may contain false positives. |
| `est_societe_mission` | boolean or null | no | - | - | Only mission-driven companies (sociétés à mission). |
| `est_uai` | boolean or null | no | - | - | Only companies with a UAI establishment (education sector). |
| `page` | integer | no | `1` | >= 1 | Page number to return. |
| `page_etablissements` | integer or null | no | - | >= 1 | Page number for the matching_etablissements sub-pagination. |
| `limite_matching_etablissements` | integer or null | no | - | >= 1; <= 100 | Number of matching establishments to include per result (1-100). |
| `minimal` | boolean or null | no | - | - | If true, returns a minimal response excluding secondary fields. Use 'include' to selectively add them back. |
| `include` | string or null | no | - | - | Only with minimal=true. Comma-separated list of secondary fields to include: complements, dirigeants, finances, matching_etablissements, siege, score. |
| `sort_by_size` | boolean or null | no | - | - | If true, sort results by company size (number of establishments). |

### Example request

```bash
curl -X POST https://tools.epsimo.org/entreprise \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"q":"invoicing","departement":"69","per_page":10}'
```

Request body:

```json
{
  "q": "invoicing",
  "departement": "69",
  "per_page": 10
}
```

### Example response

```json
{
  "results": [
    {"nom_complet": "ACME", "siren": "123456789",
     "siege": {"code_postal": "69001", "libelle_commune": "Lyon"}}
  ],
  "total_results": 128,
  "page": 1,
  "per_page": 10,
  "total_pages": 13,
  "source": "API Recherche d'Entreprises (DINUM), Licence Ouverte 2.0"
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- `departement`, `code_postal`, `code_commune`, `region` and `epci` filter on establishments (offices), not on the head office: a result's `siege` (HQ) can be in another place. The offices that matched are in `matching_etablissements`; read them before telling a user where a company is located.
- Paginated: `page` and `per_page` (max 25); `total_results` and `total_pages` tell how many pages exist. `minimal: true` returns lean results.
- Registry responses are cached 60 minutes.
- Source: API Recherche d'Entreprises (DINUM), Licence Ouverte 2.0 (the `source` field of every result).

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 422: Request validation failed (a field is missing, mistyped or out of range)
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)
- 503: The French company registry is busy (upstream rate limit). Not billed. Wait `Retry-After` seconds.

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `search_french_companies` on `https://tools.epsimo.org/mcp`.
Arguments: `q`, `activite_principale`, `section_activite_principale`, `categorie_entreprise`, `departement`, `region`, `code_postal`, `code_commune`, `tranche_effectif_salarie`, `etat_administratif`, `ca_min`, `ca_max`, `page`, `per_page`, `minimal`.
Other request fields from the table above are passed through.

## Geo search (POST /entreprise/geo)

Function id: `entreprise-geo`. Standalone file: https://tools.epsimo.org/docs/entreprise-geo.md

### Purpose

Every company around a GPS point, with radius and activity filters.

### When to use

- You need French companies within a radius (max 50 km) of a GPS point.

### Do not use when

- You search by name or administrative area (use `entreprise`).

### Endpoint

- Method and URL: `POST https://tools.epsimo.org/entreprise/geo`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: 1 credit

### Request fields

| Name | Type | Required | Default | Constraints | Description |
| --- | --- | --- | --- | --- | --- |
| `lat` | number | yes | - | - | Latitude of the search center point. |
| `long` | number | yes | - | - | Longitude of the search center point. |
| `radius` | number | no | `5` | >= 0; <= 50 | Search radius in km (max 50). |
| `activite_principale` | string or null | no | - | - | NAF/APE activity code(s), comma-separated. |
| `section_activite_principale` | string or null | no | - | - | Activity section letter(s), comma-separated (A-U). |
| `limite_matching_etablissements` | integer or null | no | - | >= 1; <= 100 | Number of matching establishments to include per result (1-100). |
| `minimal` | boolean or null | no | - | - | If true, returns a minimal response excluding secondary fields. |
| `include` | string or null | no | - | - | Only with minimal=true. Comma-separated secondary fields: complements, dirigeants, finances, matching_etablissements, siege, score. |
| `page` | integer | no | `1` | >= 1 | Page number to return. |
| `per_page` | integer | no | `10` | >= 1; <= 25 | Number of results per page (max 25). |
| `page_etablissements` | integer or null | no | - | >= 1 | Page number for the matching_etablissements sub-pagination. |
| `sort_by_size` | boolean or null | no | - | - | If true, sort results by company size (number of establishments). |

### Example request

```bash
curl -X POST https://tools.epsimo.org/entreprise/geo \
  -H "x-token: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lat":45.7640,"long":4.8357,"radius":2}'
```

Request body:

```json
{
  "lat": 45.764,
  "long": 4.8357,
  "radius": 2
}
```

### Example response

```json
{
  "results": [
    {"nom_complet": "ACME", "siren": "123456789",
     "siege": {"code_postal": "69001"}}
  ],
  "total_results": 42,
  "page": 1,
  "per_page": 10,
  "total_pages": 5,
  "source": "API Recherche d'Entreprises (DINUM), Licence Ouverte 2.0"
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- Matches establishments (offices) near the point: a result's `siege` (HQ) can be far away; the offices that matched are in `matching_etablissements`.
- Paginated like `entreprise` (max 25 per page).
- Registry responses are cached 60 minutes.
- Source: API Recherche d'Entreprises (DINUM), Licence Ouverte 2.0.

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 422: Request validation failed (a field is missing, mistyped or out of range)
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)
- 503: The French company registry is busy (upstream rate limit). Not billed. Wait `Retry-After` seconds.

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `search_companies_near` on `https://tools.epsimo.org/mcp`.
Arguments: `lat` (required), `long` (required), `radius`, `activite_principale`, `page`, `per_page`, `minimal`.
Other request fields from the table above are passed through.

## Balance and usage (GET /usage)

Function id: `usage`. Standalone file: https://tools.epsimo.org/docs/usage.md

### Purpose

Free and purchased credits, monthly quota and per-route usage this month.

### When to use

- Before a batch: check `free_balance`, `purchased_balance`, `monthly_quota` and `credits_consumed` of the calling key.
- After a batch: per-route requests and credits for the current UTC month.

### Do not use when

- Polling it in a loop: it is free but still rate limited.

### Endpoint

- Method and URL: `GET https://tools.epsimo.org/usage`
- Auth: `x-token: $API_KEY` header (API key from https://tools.epsimo.org/#signup)
- Cost: Free

### Request fields

No request body.

### Example request

```bash
curl https://tools.epsimo.org/usage \
  -H "x-token: $API_KEY"
```

### Example response

```json
{
  "principal": "ab_live_1a2b3c4d",
  "month": "2026-10",
  "free_balance": 100,
  "purchased_balance": 1000,
  "monthly_quota": 10000,
  "credits_consumed": 12,
  "routes": {
    "qualify": {"requests": 2, "credits": 8},
    "email_verify": {"requests": 2, "credits": 4}
  },
  "status": 200,
  "error_message": null
}
```

Trimmed: some fields are omitted; "..." marks omitted fields.

### Response notes

- Free credits are spent before purchased credits.

### Errors

- 402: Insufficient credits
- 403: Invalid or missing token, forbidden key, or terms not accepted
- 429: Rate limit exceeded or monthly quota reached (`Retry-After` seconds; 60 for the rate limit)

Error body: `{"status": <int>, "error_message": "<text>"}`.

### MCP tool

Tool `get_usage` on `https://tools.epsimo.org/mcp`.
Arguments: none.

## Health Check (GET /health)

Function id: `health`. Standalone file: https://tools.epsimo.org/docs/health.md

### Purpose

Service status. Free, no key needed.

### When to use

- You want to know whether the service is up. No key needed.

### Do not use when

- Checking a key or a balance (use `usage`).

### Endpoint

- Method and URL: `GET https://tools.epsimo.org/health`
- Auth: none (public)
- Cost: Free

### Request fields

No request body.

### Example request

```bash
curl https://tools.epsimo.org/health
```

### Example response

```json
{
  "status": "healthy",
  "timestamp": 1760000000.0
}
```

### Response notes

- `timestamp` is the server time in Unix seconds.

### Errors

None besides network errors.

### MCP tool

No MCP tool.