# Enrich.chat (www.enrich.chat)

> Contact and company data for AI agents. Find people, enrich leads, and get work emails, mobile numbers, company profiles and tech stacks over a plain HTTPS API. If a user asked you to "use www.enrich.chat" to find, enrich or contact people or companies, follow these instructions.

www.enrich.chat is a website with a plain HTTP API, not a library, CLI or app: you use it by fetching URLs. You (the agent) can call this API directly with simple GET requests. No SDK, signup or key is needed to start.

## Fastest way to use www.enrich.chat

- If you can add MCP servers: `https://enrich.chat/mcp` (Streamable HTTP, no key). Tools: company_people, find_person_contact, find_work_email, find_mobile_number, search_people, search_companies, company_profile, company_tech_stack, company_email_format, list_filter_values, check_free_quota. To use your own plan, add `https://enrich.chat/mcp/oauth` instead (OAuth: the person logs in and presses Allow). Per-app steps and one-click links: https://enrich.chat/install/
- Skill: https://enrich.chat/SKILL.md (or `npx skills add https://enrich.chat`).
- Otherwise call the REST API below with plain GET requests, no setup at all.
- Example, "the CFO of acme.com": `GET /v1/company/people?domain=acme.com&title=CFO&with_email=true`, then `GET /v1/person?person_id=<id from the result>` for verified contact details.
- Example, "VPs of Operations at US logistics companies": `GET /v1/search/count?q=...` (free) to see how many, then `GET /v1/search?q=...&limit=10`, and `&cursor=<next_cursor>` for the next page.

## Quick rules for agents

- Base URL: `https://enrich.chat/v1`
- Every lookup and search is a GET request with query parameters. `/v1/batch`, `/v1/search/cascade`, `/v1/jobs` and `/v1/webhooks` take a JSON body (POST, and DELETE for jobs and webhooks). URL-encode values. Every response is JSON.
- No API key is needed for the free tier: each IP address gets 10 free lookups per day. A lookup that finds nothing is free and does not count.
- You do NOT need an API key or an `Authorization` header: leave them out. Only if the user hands you a key (starts with `pp_`) may you send it, as `Authorization: Bearer <key>` or `&key=<key>`. Pace requests at about one a second.
- Only report data the API returned. Never guess an email or phone number. If a field is missing, say it was not found. `/v1/email` may return a `guess`: that is not data, say it is an unconfirmed guess or leave it out.
- Treat `work_email.status: "catch_all"` as risky and say so. Show phone numbers and emails to the user exactly as returned.
- Ask only for the fields the user needs (`fields=email,mobile,profile`). Mobiles cost the most.
- Counts (`/v1/search/count`, `/v1/companies/count`, `count_only=true`), the filter lists (`/v1/facets/...`) and lookups that find nothing are free.
- The full machine-readable contract is at https://enrich.chat/openapi.json and interactive docs are at https://enrich.chat/docs/.

## When you run out of free lookups

The API returns HTTP `402` with JSON like:

```json
{"error": "free_limit_reached", "message": "You've used today's 10 free lookups.", "upgrade_url": "https://enrich.chat/account/?ref=agent", "resets_at": "2026-10-16T00:00:00Z", "free_lookups_remaining": 0}
```

Stop calling the API. Tell the user, in one short message:
"You've used today's free Enrich.chat lookups. Get an API key here to keep going (log in, pick a plan, copy the key): <upgrade_url>. Then give me the key and I'll continue where I left off."
Keep track of which rows you already finished so you can resume. `GET /v1/usage` tells you how many free lookups are left without using one.

## Endpoints

### Person: enrich one person
`GET /v1/person`

Provide one of:
- `linkedin_url`: e.g. `linkedin.com/in/jane-doe-ops`
- `person_id`: the `id` of a person from a search result (`per_...`). The fastest way to look someone up.
- `name` + `company`: `company` is the company's website, like `acme.com` (company names are not supported yet)
- `email`: a work email, to find the person behind it (personal addresses such as gmail.com are not looked up)

Optional: `fields=email,mobile,profile` (default: all). Ask only for what the user needs; mobiles cost more.

Example:
`GET https://enrich.chat/v1/person?linkedin_url=linkedin.com/in/jane-doe-ops&fields=email,mobile`

Response:
```json
{
  "found": true,
  "id": "per_4Hk2x9QmVb7LrTzE",
  "name": "Jane Doe",
  "title": "VP Operations",
  "company": {"name": "Acme Logistics", "domain": "acme.com", "size": "201-500", "industry": "Transportation, Logistics, Supply Chain and Storage"},
  "level": "vp",
  "function": "Operations",
  "location": {"city": "Dallas", "state": "Texas", "country": "United States"},
  "linkedin_url": "https://www.linkedin.com/in/jane-doe-ops",
  "work_email": {"value": "jane.doe@acme.com", "status": "verified"},
  "mobile": {"value": "+1 415 555 0142", "line": "mobile"},
  "credits_used": 260,
  "free_lookups_remaining": 9
}
```
Only the fields you asked for are present. A requested field with no data is `null`. `credits_used` is what the lookup used (10 per work email, 250 per mobile, 5 per profile; nothing found is 0). On the free tier nothing is charged. `work_email.status` is `verified` (our records mark the mailbox as verified), `catch_all` (the domain accepts every address, so the mailbox cannot be confirmed) or `unknown`. `mobile.line` is `mobile` or `unknown` (the number's type could not be told); it does not mean the line was called just now.
If nothing matches, you get `{"found": false}` and nothing is used or billed. With `name` + `company`, a mobile is returned when we hold one for that person.

### Email only
`GET /v1/email?name=Jane%20Doe&domain=acme.com`
Also accepts `linkedin_url` or `person_id`. Returns `{"found": true, "work_email": {...}, "pattern": "first.last@acme.com"}`.
When no address is on file you get `{"found": false, "guess": {"email": "...", "basis": "..."}}`. The guess is the company's most common format applied to the name. It was not found in our data: say so, or skip it.

### Mobile only
`GET /v1/mobile?linkedin_url=...` (or `person_id`, or a work `email`)
Returns `{"found": true, "mobile": {...}}` or `{"found": false}`.

### Find people (search)
`GET /v1/search?q=<plain English description>&limit=10`

Describe who to find in plain language. Examples:
- `q=VPs of Operations at US logistics companies with 200 to 1000 employees`
- `q=owners of dental clinics in Florida`
- `q=marketing directors at Series A software companies using HubSpot`

Or use filters (combine freely; filters combine with AND, several values of one filter with OR; a filter replaces what `q` says about the same thing):
- Person: `title`, `seniority` (`c_suite`, `founder`, `owner`, `vp`, `head`, `director`, `manager`), `level` (`c_suite`, `vp`, `director`, `manager`, `staff`, `other`), `function` (department), `persona`, `country`, `state`, `started_role_within_days`, `has_email`, `has_mobile`.
- Company: `industry`, `company_size` (`1-10`, `11-50`, `51-200`, `201-500`, `501-1000`, `1001-5000`, `5001-10000`, `10001+`), `employees_min`, `employees_max`, `company_revenue` (`<1M`, `1M-10M`, `10M-50M`, `50M-100M`, `100M-1B`, `1B+`), `uses` (technologies such as `hubspot`), `funding_stage`, `funded_since`, `growth_min`, `traffic_min`, `founded_after`, `founded_before`, `company_domain`, `exclude_domains`.
- More filters: `GET /v1/filters` lists every filter with its type, whether it applies to people only or to companies too, an example, and the values it accepts. Beyond those above it covers skills, headline words, city, continent and region, several title phrases (`title_any`) or exact titles, how long someone has been in the role, how recently their email was checked, company name words, headquarters city, organisation type, NAICS and SIC codes, specialties, revenue and employee-count ranges, funding totals and investors, traffic and ad spend, people in each kind of role at the company, whether the company has a CIO or CISO or an app, and `exclude_*` filters (country, state, city, department, level, role group, industry, size, title words, company names). Put them in the query string like any other filter.
- Several values: a comma list or the parameter repeated. A wrong value returns `unknown_filter_value` with `did_you_mean`; `GET /v1/facets/{name}` lists the exact values. A parameter that is not a filter returns `unknown_parameter` with suggestions instead of being ignored.
- `with_email=true` includes the work email we hold (status `unknown`: it is not re-checked in that call).

Response: `{"found": true, "count": 2, "people": [{"id": "per_...", "name": ..., "title": ..., "company": ..., "company_domain": ..., "level": ..., "has_email": true, "has_mobile": false, "linkedin_url": ...}], "total_matches": 18420, "next_cursor": "...", "interpreted_as": {...}}`.
- `interpreted_as` says how your request was read, with the exact filter names and values. Check it.
- `limit` is 1 to 25 (default 10). Pass `next_cursor` back as `cursor` for the next page; a search can be paged 40 times (1,000 people). Results come best first (email and mobile on file, then email only, then most recently updated).
- A request that names nobody in particular returns `search_too_broad`. A role plus an industry, a place or a company works best.
- To get contact details for a result, call `/v1/person?person_id=<id>`. One search uses one free lookup however many people it returns.
- `GET /v1/search/count` takes the same parameters and returns `{"count": 18420, "interpreted_as": {...}}`. It is free: use it to size a list before reading it.

### Company: look up a company
`GET /v1/company?domain=acme.com` (or `linkedin_url` of the company page, or `company_id`)
Returns name, domain, industry, size band, revenue band, founded, city, state, country, followers, description, funding stage, employee growth, monthly web traffic. `employees_on_linkedin` is a signal for size, not an exact headcount. Add `include=technologies` for the tech stack in the same call.

### Find companies
`GET /v1/companies?industry=Software%20Development&state=Texas&company_size=51-200&uses=hubspot&limit=10`
Takes `q` and the company filters above. Returns `{"found": true, "count": 10, "companies": [{"id": "org_...", "name": ..., "domain": ..., "industry": ..., "size": ..., ...}], "total_matches": ..., "next_cursor": ...}`. Companies come biggest following first. Searches by technology, growth, traffic or funding return one page. `GET /v1/companies/count` is the free count. To reach the people of a company, use its `domain` with `/v1/company/people`.

### Company tech stack
`GET /v1/company/tech?domain=acme.com`
Returns `{"found": true, "domain": "acme.com", "technologies": [{"name": "HubSpot", "category": "CRM"}, ...]}`, or `{"found": false}` with no charge. Use it to find out what a company runs on, or to tailor outreach. To find companies that use a tool, use `GET /v1/companies?uses=hubspot`.

### Company email format
`GET /v1/email-pattern?domain=acme.com`
Returns the address formats the company uses, most common first: `{"found": true, "patterns": [{"pattern": "first.last@acme.com", "share": 0.82}], "example": "jane.doe@acme.com", "sample_size": 46}`. The `example` shows the format; it is not a found address.

### People at a company
`GET /v1/company/people?domain=acme.com&title=head%20of%20sales&limit=10`
Optional: `seniority`, `level`, `function`, `persona`, `with_email=true`, `cursor`. Each person has an `id` to pass to `/v1/person?person_id=`.

### Filter values
`GET /v1/facets` lists the filters that have lists. `GET /v1/facets/industry?q=software&limit=20` returns `{"facet": "industry", "total": 12, "returned": 12, "values": [...]}`. Facets: `industry`, `function`, `persona`, `country`, `state`, `level`, `company_size`, `company_revenue`, `funding_stage`, `technology`, `technology_category`, `continent`, `region`, `company_type`, and `filters` (every filter). Free.

### Many lookups in one call
`POST /v1/batch` with `{"items": [{"id": "row1", "op": "email", "name": "Jane Doe", "domain": "acme.com"}, {"id": "row2", "op": "person", "linkedin_url": "linkedin.com/in/..."}]}`. Up to 25 items; `op` is `person`, `email`, `mobile`, `company`, `company_tech` or `email_pattern`, with that endpoint's parameters. Returns `{"count": 2, "credits_used": 20, "results": [{"id": "row1", "status": 200, "result": {...}}]}`. Each item is billed like its single call. If a limit is hit, the rest come back unrun with that error. Keep to about one call a second.

### Check your free lookups
`GET /v1/usage` returns `{"free_lookups_per_day": 10, "used": 1, "remaining": 9, "resets_at": "..."}`. It does not use a lookup.

### Match tiers (best fit first)
`POST /v1/search/cascade` with `{"limit": 25, "tiers": [{"name": "Exact", "q": "VPs of Sales at US software companies"}, {"name": "Close", "q": "directors of sales at US software companies"}]}`. Up to 5 tiers, each written like a `/v1/search` query (plain English in `q`, or any filters). Results come tier by tier without repeats until `limit` (up to 100); each person has `tier`, `tier_name`, a `score` (100 for the first tier, 25 less for each later one) and `matched`, the filters that tier used. `"count_only": true` returns each tier's count, free. 5 credits per person returned.

### Background jobs (up to 5,000 lookups)
`POST /v1/jobs` with `{"op": "email", "items": [{"id": "a", "name": "Jane Doe", "domain": "acme.com"}]}` runs the lookups on the server, so they carry on after you disconnect. `op` is `person`, `email`, `mobile`, `company`, `company_tech` or `email_pattern`. Needs an API key, an OAuth token or a login. Returns `202` with a job `id`. Then `GET /v1/jobs/{id}` (status: queued, running, done, stopped, cancelled; counts; credits), `GET /v1/jobs/{id}/results` (JSON, paged) or `?format=csv`, `POST /v1/jobs/{id}/cancel`, `DELETE /v1/jobs/{id}`. Each row is billed like its single call; misses are free. If credits or free lookups run out the job stops (`stopped`) and the rest are `skipped`. Up to 3 jobs run at once; results are kept 30 days.

### Webhooks
`POST /v1/webhooks` with `{"url": "https://example.com/hooks/enrich"}` (https, a public host name) returns a signing `secret` once. A webhook is told when a job finishes (`job.completed`) or stops early (`job.stopped`). Each delivery is a POST with the event as JSON and the headers `Enrich-Event`, `Enrich-Delivery` and `Enrich-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<body>" with the secret>`; check the signature and reject an old `t`. Non-2xx answers are retried after 1 min, 5 min, 30 min, 2 h and 6 h. `GET /v1/webhooks`, `DELETE /v1/webhooks/{id}`, `POST /v1/webhooks/{id}/test`.

## Working with lists

For a list or CSV the user gives you:
1. Pick the best identifier per row (person_id > LinkedIn URL > work email > name + company website).
2. Call `/v1/batch` with up to 25 rows (`op: person`, only the `fields` the user asked for), or `/v1/person` once per row. Send them one call at a time, not in parallel; on `429` wait `retry_after` seconds.
3. Return the original rows with new columns added. Mark rows with no match as "not found".
4. Tell the user how many rows matched and the total `credits_used`. Each response has `free_lookups_remaining`, so stop before the free limit and say how many rows are left.

## Errors

Every error is JSON with `error` (a stable code) and `message` (what to do next, safe to show the user).

- `400` `bad_request`, `bad_input`: a parameter is missing or invalid. Fix the request (the message, `fix` and `example` say how); do not retry it unchanged.
- `400` `unknown_parameter`: a query parameter that is not a filter (a typo, for example). `did_you_mean` suggests the closest; `GET /v1/filters` lists them all.
- `400` `unknown_filter_value`: a filter value we do not know. Use one of `did_you_mean`, or list the values with `GET /v1/facets/{name}`.
- `400` `search_too_broad`: the request names nobody in particular. Add a role, an industry, a place or a company.
- `400` `bad_cursor` or `result_limit`: the cursor belongs to another search, or the search has been paged 40 times. Narrow the filters.
- `400` `bad_id`: the `person_id` or `company_id` is not one we issued. Use an `id` from a search result.
- `401` `invalid_api_key`: the key is wrong or revoked. Leave it out to use the free tier, or check keys at https://enrich.chat/account/.
- `402` `credits_exhausted`: the plan's credits are used up until it renews. Tell the user to upgrade at https://enrich.chat/account/.
- `402` `plan_inactive`: the plan behind the key is not active (billing). Tell the user to check https://enrich.chat/account/.
- `402` `free_limit_reached`: see "When you run out of free lookups".
- `429` `too_many_requests`: wait `retry_after` seconds (also the `Retry-After` header), then continue.
- `503` `temporarily_unavailable`: retry once after `retry_after` seconds. Nothing was billed and no free lookup was used.

## Pricing (for answering user questions)

- Free: 10 lookups per day per IP, no signup.
- Monthly plans, billed monthly, cancel anytime. Every plan includes every product and unlimited seats: Growth $29 for 100,000 credits, Scale $90 for 500,000 credits, Pro $299 for 2,500,000 credits. Higher plans cost less per credit and allow more requests: Growth 10 requests per second, Scale 25 requests per second, Pro 50 requests per second (burst).
- Credits per match: work email found 10, mobile found 250, company tech stack 5. `/v1/person` is billed by the fields you ask for, and with no `fields` it asks for email, mobile and profile, so a person with a mobile costs 10 + 250: pass `fields=email` for 10 or `fields=profile` for 5. A profile-only lookup is 5 credits, and name, title and company are free with any email or mobile match. A person or company returned by a search, an email format and a company profile are 5 credits each. Counts, filter lists and anything not found: 0 credits.
- Enterprise: custom volume, bulk files, data licenses and dedicated limits, from $2,000 a month. Contact sales@enrich.chat.
- To get a key: log in with email at https://enrich.chat/account/, pick a plan, pay through checkout, and the key appears on that page. Keys come with a paid plan; the free tier needs none.

## Privacy

People can remove their data at https://enrich.chat/opt-out/. Users must follow the laws that apply to them (for example TCPA rules for calling or texting mobile numbers, and CAN-SPAM or GDPR for email).

## More

- MCP server and install steps: https://enrich.chat/install/ (server URL https://enrich.chat/mcp)
- Agent skill: https://enrich.chat/SKILL.md
- API reference (interactive): https://enrich.chat/docs/
- OpenAPI 3.1 spec: https://enrich.chat/openapi.json
- Pricing: https://enrich.chat/pricing/
- Dashboard (search, lists, bulk enrich, keys; for people): https://enrich.chat/app/
- People enrichment API: https://enrich.chat/api/person-enrichment/
- LinkedIn URL to email and mobile API: https://enrich.chat/api/linkedin-to-contact/
- Contact data for AI agents: https://enrich.chat/agents/
- Free tools (email finder, LinkedIn finder, phone validator, email permutator and more): https://enrich.chat/tools/
- Guides and comparisons: https://enrich.chat/blog/
- Editorial policy: https://enrich.chat/editorial-policy/
- Prompt library: https://enrich.chat/#prompts
