Metadata-Version: 2.5
Name: langchain-reefapi
Version: 0.1.0
Summary: LangChain tools for ReefAPI: one API key for 600+ site-specific, live web-data APIs (Amazon, eBay, Zillow, Reddit, Google Maps and more).
Project-URL: Homepage, https://reefapi.com
Project-URL: Documentation, https://reefapi.com/docs
Project-URL: Pricing, https://reefapi.com/pricing
Project-URL: Python SDK, https://pypi.org/project/reefapi/
Project-URL: Status, https://api.reefapi.com/status
Author-email: ReefAPI <support@reefapi.com>
License-Expression: MIT
License-File: LICENSE
Keywords: agents,amazon,ebay,google maps,langchain,langchain-tools,live data,mcp,reddit,reefapi,scraper api,tools,web data,web scraping,zillow
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: langchain-core<2.0.0,>=1.0.0
Requires-Dist: reefapi<0.2,>=0.1.0
Description-Content-Type: text/markdown

# langchain-reefapi

LangChain tools for [ReefAPI](https://reefapi.com). ReefAPI is one API key for 600+ site-specific,
live web-data APIs ("engines"): Amazon, eBay, Zillow, Reddit, Google Maps, Trustpilot, LinkedIn Jobs,
Booking and hundreds more. Each engine fetches its website in real time and returns JSON. Failed calls
are not charged.

This package gives a LangChain agent three tools that cover the whole catalog:

| Tool | Name the model sees | What it does | Key needed |
|---|---|---|---|
| `ReefAPISearchEngines` | `reefapi_search_engines` | Find the engine for a website or a data need (keyword search over the live catalog) | no |
| `ReefAPIGetSchema` | `reefapi_get_schema` | An engine's actions, or one action's parameters, allowed values and example | no |
| `ReefAPICall` | `reefapi_call` | Run `engine` / `action` with `params`, return the response `data` as JSON | yes |

`ReefAPIToolkit` returns all three with one shared configuration. The tools are built on the official
Python SDK, [`reefapi`](https://pypi.org/project/reefapi/), so retries for retryable errors and the
client-side rate limit (30 requests per 3 seconds per key) come with them.

## Install

```bash
pip install -U langchain-reefapi
```

Python 3.10+. Get an API key at [reefapi.com](https://reefapi.com) and set it in the environment:

```bash
export REEFAPI_API_KEY="your-key"     # REEFAPI_KEY works too
```

or pass it to the constructor: `ReefAPIToolkit(api_key="...")`. The key is held as a `SecretStr` and
is left out of `repr()`, logs and serialized tool state. The two discovery tools work without a key.

## Example 1: an agent that picks the engine itself

```bash
pip install -U langchain-reefapi "langchain[anthropic]"
```

```python
from langchain.agents import create_agent
from langchain_reefapi import ReefAPIToolkit

agent = create_agent(
    model="claude-sonnet-4-6",          # any chat model with tool calling
    tools=ReefAPIToolkit().get_tools(),
    system_prompt="Use the ReefAPI tools for live data from websites. "
                  "Find the engine first, read its schema, then call it.",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What are the 3 cheapest iPhone 13 Pro listings on eBay right now?"}]}
)
print(result["messages"][-1].content)
```

A typical run: the model calls `reefapi_search_engines` (for example with "ebay listings"), then
`reefapi_get_schema("ebay", "search")`, then `reefapi_call("ebay", "search", {"query": "iphone 13 pro", "sort": "price_low"})`.
If it sends a bad parameter, the tool returns the error text (code, whether a retry can help,
request id) to the model instead of raising, and the model can correct itself. That failed call is
not charged.

## Example 2: the tools one by one

```python
import json
from langchain_reefapi import ReefAPICall, ReefAPIGetSchema, ReefAPISearchEngines

# 1. which engine? (no key needed)
found = json.loads(ReefAPISearchEngines().invoke({"query": "sold prices on ebay", "max_results": 3}))
print([e["engine"] for e in found["engines"]])          # ['ebay', 'cardladder', 'ebay-sold']

# 2. which parameters? (no key needed)
schema = json.loads(ReefAPIGetSchema().invoke({"engine": "ebay", "action": "search"}))
print(schema["required_params"], schema["example_params"])   # ['query'] {'query': 'iphone 13 pro'}

# 3. call it (uses your key)
data = json.loads(ReefAPICall().invoke(
    {"engine": "ebay", "action": "search", "params": {"query": "iphone 13 pro", "max_results": 5}}
))
for item in data["results"]:
    print(item["title"], item["price"]["value"], item["price"].get("currency"))
```

Without `action`, `reefapi_get_schema` lists every action of the engine. The same information is on
each engine's docs page, for example [reefapi.com/docs/ebay](https://reefapi.com/docs/ebay).

## Example 3: full data as a tool artifact, sync or async

When the tool runs from a tool call (which is how agents run it), it returns a `ToolMessage`. The
`content` is what the model reads: the response `data` as JSON, cut at `max_output_chars`
(default 50,000) so one large page of results cannot flood the context. The `artifact` holds the full,
uncut `{"data": ..., "meta": ...}` for your own code.

```python
import asyncio
from langchain_reefapi import ReefAPICall

call = ReefAPICall(max_output_chars=4000)
tool_call = {
    "type": "tool_call",
    "id": "call-1",
    "name": "reefapi_call",
    "args": {"engine": "trustpilot", "action": "company/reviews",
             "params": {"company": "amazon.com", "maxReviews": 20}},
}

msg = call.invoke(tool_call)
print(msg.content[:300])                        # what the model sees (at most 4,000 characters)
company = msg.artifact["data"]["results"][0]["company"]
print(company["name"], company.get("trust_score"))
print(msg.artifact["meta"]["request_id"])       # quote this when contacting support

msg = asyncio.run(call.ainvoke(tool_call))      # every tool also has an async path
```

## Errors

Every error the gateway or the SDK reports becomes a `ToolException` whose text carries the error
code (`INVALID_PARAM`, `MISSING_PARAM`, `UNKNOWN_API`, `RATE_LIMITED`, `QUOTA_EXCEEDED`,
`TARGET_BLOCKED`, `UPSTREAM_TIMEOUT`, `MISSING_API_KEY`, ...), `retryable=true|false`, the HTTP status
and the request id, for example:

```
ReefAPI error INVALID_PARAM: sort must be one of ... retryable=false. http_status=400. request_id=... Check the parameter names and allowed values with reefapi_get_schema. Failed calls are not charged.
```

By default (`handle_tool_error=True`) that text goes back to the agent as the tool result. Set
`handle_tool_error=False` to get the exception instead; it also has `.code`, `.retryable` and
`.request_id` attributes.

## Options

All three tools and the toolkit accept:

| Argument | Default | Meaning |
|---|---|---|
| `api_key` | `REEFAPI_API_KEY`, then `REEFAPI_KEY` | Your ReefAPI key |
| `base_url` | `https://api.reefapi.com` (or `REEFAPI_BASE_URL`) | Gateway URL |
| `timeout` | `180` | Seconds per request. Some engines render pages in a real browser and take over a minute |
| `max_retries` | `2` | Automatic retries for errors marked retryable and for HTTP 429 |
| `max_output_chars` | `50000` | (`ReefAPICall`, toolkit) Cut the model-facing text here; `None` never cuts |
| `client` / `async_client` | built for you | Your own `reefapi.ReefAPI` / `reefapi.AsyncReefAPI` (proxies, custom transport) |

The catalog used by `reefapi_search_engines` is fetched once (about 1.5 MB, no key) and cached for an
hour per process.

## Credits

Discovery (`reefapi_search_engines`, `reefapi_get_schema`) is free. Each successful `reefapi_call`
costs credits on your ReefAPI account; failed calls are not charged. Plans and free credits:
[reefapi.com/pricing](https://reefapi.com/pricing).

## MCP

If your agent runs in an MCP client (Claude, Cursor, ChatGPT and others), you can connect the hosted
ReefAPI MCP server at `https://api.reefapi.com/mcp` instead of installing this package. It has the
same flow (`search_engines`, `get_engine_schema`, `get_action_schema`, `call_engine`). Use this
package when you build the agent yourself with LangChain or LangGraph.

## Links

- ReefAPI: https://reefapi.com
- Docs (every engine, every action): https://reefapi.com/docs
- Python SDK: https://pypi.org/project/reefapi/
- Status: https://api.reefapi.com/status

## Development

```bash
pip install -e . pytest pytest-asyncio pytest-socket "langchain-tests==1.1.9" "langchain>=1,<2"
pytest                                            # unit tests + LangChain standard tests, offline
REEFAPI_LIVE_TEST=1 REEFAPI_API_KEY=... pytest tests/integration_tests   # live, about 7 billable calls
```

On Linux and macOS, `pytest --disable-socket --allow-unix-socket` proves the unit tests make no
network calls.

## License

MIT
