Integrations · LangChain

LangChain Enrichment — Typed Tools and Chains over RichAPI

Define RichAPI endpoints as @tool functions with Pydantic argument schemas so the model fills typed fields instead of guessing JSON. Most enrichment does not need an agent at all, and a chain is cheaper and deterministic. Use tool-calling only where the routing is genuinely ambiguous.

Start free — 25 credits

Last updated September 22, 2026

Connect it.

  1. 01

    Create a RichAPI account at app.richapi.ai/signup and copy your API key.

    25 free credits, no card.

  2. 02

    pip install langchain langchain-core, and export RICHAPI_KEY.

    Add langchain-mcp-adapters instead if you would rather load the whole catalog from our MCP server than hand-write wrappers.

  3. 03

    Write one @tool per endpoint with a Pydantic args_schema.

    The field descriptions are the prompt. company_domain described as 'bare domain, no scheme or www' is the difference between acme.com and https://www.acme.com/ and a wasted call.

  4. 04

    Bind them with llm.bind_tools([...]) for routing, or call the same functions directly inside an LCEL chain when the sequence is fixed.

  5. 05

    Parse the response with a Pydantic output model so a miss is a typed None rather than a string the next step has to interpret.

What you can ask for.

Copy, paste, edit the brackets, run.

Chain: domain in → enrich_company → structured ICP score out, as a Pydantic model with a reason field.
Router: given a partial contact, decide between email_finder, find_linkedin_url_by_name and find_linkedin_url_by_email, then run it.
RAG over your own account notes, with a live enrich_company call to refresh headcount and industry before the model answers.
Batch 500 rows through a RunnableLambda calling email_verifier, split into valid, catch-all and invalid.
Tool-calling agent that researches an account and refuses to answer a field it could not retrieve.

Why it matters

LangChain's real contribution to enrichment is not the agent loop. It is typed arguments and typed outputs. A model that has to satisfy a Pydantic schema sends fewer malformed requests, and every malformed request to a per-call endpoint is a credit you paid for nothing.

LangChain enrichment: typed arguments are what save you credits

There is no RichAPI package in `langchain-community`. You define the tools, and LangChain gives you the one thing that matters for a paid API: the model fills a schema you wrote rather than assembling JSON from vibes.

A tool with a schema that actually constrains

```python import os, requests from typing import Optional from pydantic import BaseModel, Field from langchain_core.tools import tool class EmailResult(BaseModel): email: Optional[str] = None status: Optional[str] = None found: bool providers_tried: list[str] = [] @tool(args_schema=...) def find_work_email(full_name: str, company_domain: str) -> EmailResult: """Find a verified work email. company_domain must be a bare domain such as acme.com. No scheme, no www, no path.""" r = requests.post( "https://api.richapi.ai/api/v1/email_finder", headers={"x-api-key": os.environ["RICHAPI_KEY"]}, json={"full_name": full_name, "company_domain": company_domain}, ).json() if not r.get("success"): return EmailResult(found=False, providers_tried=[a.get("status") for a in r.get("execution_log", [])]) return EmailResult(found=True, email=r["data"]["email"], status=r["data"]["status"]) ``` The docstring is the tool description the model reads, and the sentence about bare domains is load-bearing. Models hand APIs `https://www.acme.com/about` constantly. On `email_finder` a malformed domain costs nothing, because the waterfall soft-fails free. On `enrich_profile`, which bills on any 2xx, it costs you a credit to learn that the model added a trailing slash. Returning a typed `EmailResult` rather than a dict means the downstream step branches on `found`, and a miss cannot silently become the string `"None"` in a merge field.

Do not reach for an agent first

A lot of LangChain enrichment code is a tool-calling agent doing work that has no decisions in it. If your pipeline is *domain → company → decision-maker → email → verify*, that is a chain. Write it as one: ```python pipeline = ( RunnableLambda(clean_domain) | RunnableLambda(enrich_company) | RunnableLambda(top_contact) | RunnableLambda(find_work_email) ) rows = pipeline.batch(domains, config={"max_concurrency": 8}) ``` A chain makes exactly the calls it is written to make. An agent makes the calls it decides to make, and you find out how many on the invoice. Reach for `bind_tools` when the routing is genuinely ambiguous. You have a name and maybe a domain and maybe a LinkedIn URL, and something has to choose between `email_finder`, `find_linkedin_url_by_name` and `find_linkedin_url_by_email`. That is a real decision. "Call these four things in order" is not. The structured-output side is the same argument pointed the other way. Wrap the enriched company in `llm.with_structured_output(ICPScore)` and you get a typed score with a reason field, from live data, without an agent loop anywhere.

MCP, if you would rather not maintain wrappers

`langchain-mcp-adapters` loads a remote MCP server's tools as LangChain tools. Ours is at `https://mcp.richapi.ai/mcp` with the same `x-api-key` header and the same credit pool, so the whole catalog arrives typed and you maintain none of it. The tradeoff is the tool descriptions become ours rather than yours, and the domain-format sentence above is exactly the kind of thing you want to own. Wrappers for a narrow production pipeline, MCP for exploration.

Cost

| Endpoint | Cost | Miss behaviour | | --- | --- | --- | | `email_finder` | `5 credits` | free | | `email_verifier` | `2 credits` | free | | `phone_finder` | `25 credits` | free | | `enrich_company` | `1 credit` | billed on 2xx | | `enrich_profile` | `1 credit` | billed on 2xx | | `find_linkedin_url_by_name` | `4 credits` | billed on 2xx | | `people_search` | `0.1 credits per result` | billed on 2xx | Full price only on results is true of the waterfall column and nothing else. A non-2xx never bills on any endpoint. Tiers on [/pricing](/pricing). Your LangSmith traces can stop saying "tool returned null" and start naming the providers that had nothing. Surface `execution_log` in your tool's return value; a multi-provider waterfall response puts one entry in it per provider attempt, each with a status.

Where we stop with LangChain

Lookups only. No sending, no sequencing, no CRM writes, no prospecting UI. We do not publish the provider roster either. It changes, and the `execution_log` is a better answer than a list on a page. Related, from the [integrations index](/integrations): [CrewAI](/integrations/crewai) for role-based crews, [LangGraph](/integrations/langgraph) when the loop needs explicit state, [OpenAI Agents SDK](/integrations/openai-agents), and [person enrichment API](/api/person-enrichment) for the raw field shapes.

LangChain FAQ

**Is there a langchain-community RichAPI integration?** No. `@tool` wrappers or `langchain-mcp-adapters`. **Does `enrich_company` take a domain?** It takes a LinkedIn company URL. If you have a name, resolve it first. This trips up more integrations than anything else in the catalog. **Async?** Define the tool with `async def` and use `ainvoke` / `abatch`. It is a plain HTTP POST underneath. **How do I stop an agent looping on a miss?** Return `found=False` with the provider statuses rather than raising. A tool that errors invites a retry; a tool that reports an exhausted waterfall does not. **Can I use the same key from a notebook and production?** Yes, one pool. Name separate keys per surface if you want usage split out. See [per-client API keys for agencies](/use-cases/per-client-api-keys-for-agencies).

Start with LangChain

25 free credits, no card. Copy the tool, run the chain over ten domains, and read the traces before you write the agent.

Frequently asked.

Does LangChain see my RichAPI key?
No — LangChain Enrichment — Typed Tools and Chains over RichAPI authenticates through the connection you set up, using the same key and credit pool as the REST API. Revoking access from your RichAPI dashboard disconnects it immediately.
Does this cost more than using the REST API directly?
No — MCP and REST share the same credit pool and the same published endpoint rates. There's no separate MCP surcharge.

More integrations

Try it with 25 free credits.