Liquid discovers any HTTP API, maps it to the shape you ask for, and serves typed data to your agent. AI runs once at setup — every sync after is deterministic and costs no model tokens. Token-aware search, cross-API normalization, and self-healing come built in.
Measured on realistic agent tasks against deterministic fixtures. See full benchmarks →
AI discovers and maps an API once (or reuses the catalog). Everything after is a deterministic runtime — every layer optimizes for the agent.
Pull from the 2,500+ API catalog, or discover on the fly: OpenAPI → GraphQL → REST heuristic → browser. Cheapest method first.
AI maps fields to the shape you asked for, once. Normalize shapes (Money, DateTime, pagination), compile intent verbs, build token estimators — all saved into a deterministic adapter.
Expose as framework-native tools. Every call runs the token-aware runtime — search, aggregate, estimate, budget, truncate — no model in the loop.
Errors carry structured next_action. Schema drift triggers auto-repair. Rate limits surface as retry_after. The agent never reads stack traces.
Token budgets. Cross-API cognitive load. Canonical intents. Error recovery. Cost prediction. Ambient state. All at the transformation layer — not in your prompt.
Filter, project, aggregate, text-search — all before bytes reach the context window. Budget caps and fetch_until predicates end the “fetch everything, filter in prompt” anti-pattern.
# −98% tokens vs blind fetch await liquid.search( adapter, "/orders", where={"total_cents": {"$gt": 10000}}, limit=20, )
Stripe, PayPal, Square, Adyen all collapse into one Money(amount_cents, currency). Dates become UTC datetime. Pagination envelopes flatten. Your agent writes one parser, not four.
# normalize on the client; connect by URL liquid = Liquid(..., normalize_output=True) adapter = await liquid.get_or_create( "https://api.stripe.com", target_model={"amount_cents": "int"}, ) # → Money(amount_cents=9999, currency="USD")
charge_customer() anywhereIntent-level verbs like charge_customer, create_ticket, post_message work across vendors. Swap Stripe for PayPal with one config change — the agent's tool call doesn't change.
await liquid.execute_intent( "charge_customer", {"customer_id": "cus_42", "amount_cents": 9999, "currency": "USD"} )
401 → store_credentials. 404 → repair_adapter. 429 → retry_after_seconds. Agents dispatch the suggested tool without parsing error text. No human in the loop for known failure modes.
try: await liquid.fetch(adapter) except AuthError as e: # structured, not a string agent.call(e.recovery.next_action)
estimate_fetch() returns items, bytes, tokens, credits, latency — with zero HTTP calls. Tool metadata (cost_credits, cached, idempotent, side_effects) lets the agent plan routes, not hope for the best.
est = await liquid.estimate_fetch( adapter, "orders", ) if est.expected_tokens > budget: # switch to aggregate / search
to_tools() auto-attaches liquid_check_quota, liquid_check_rate_limit, liquid_health_check, liquid_estimate_fetch, liquid_search_nl, and more. The agent discovers state rather than carrying it in context.
tools = adapter.to_tools( format="anthropic", ) # includes ambient introspection # tools alongside adapter tools
Run python -m benchmarks.run against the fixtures — fresh numbers, same delta, every time. No cherry-picked marketing graphs.
| Task | Baseline | With Liquid | Delta |
|---|---|---|---|
| Find 10 orders over $100 | 75,482 tok | 1,519 tok | −98% |
| Revenue by status (aggregate) | 75,482 tok | 115 tok | −100% |
| Fetch customer id + email only | 424 tok | 12 tok | −97% |
| Find the shipping ticket (text search) | 14,588 tok | 154 tok | −99% |
| Stripe ↔ PayPal field consistency | 0.11 overlap | 1.00 overlap | 9× |
| Skip wasted call via estimate | 14,943 tok | 0 tok | −100% |
| max_tokens=2000 budget cap | 14,943 tok | 1,999 tok | −87% |
| Recover from 401 | no next_action | structured | — |
Methodology, fixtures, and raw JSON in benchmarks/RESULTS.md.
to_tools() emits the shape your framework expects — with ambient introspection tools included.
Normalized output, token-aware search, structured recovery — in one example.
# pip install liquid-api from liquid import Liquid from liquid._defaults import InMemoryVault, InMemoryAdapterRegistry, CollectorSink liquid = Liquid( llm=my_llm, vault=InMemoryVault(), sink=CollectorSink(), registry=InMemoryAdapterRegistry(), normalize_output=True, ) # 1. Discover + map any API once — connect by URL, no pre-built integration adapter = await liquid.get_or_create( "https://api.stripe.com", target_model={"id": "str", "amount_cents": "int", "currency": "str"}, ) # 2. Budgeted, server-side search — not "fetch everything, filter in prompt" try: charges = await liquid.search( adapter, "/charges", where={"amount_cents": {"$gt": 10_000}}, fields=["id", "amount_cents", "currency"], limit=20, ) except LiquidError as e: # 3. Structured recovery — dispatch the suggested tool, no text parsing agent.call(e.recovery.next_action) # → store_credentials(...) # 4. Hand the whole kit to the agent, one call tools = adapter.to_tools(format="anthropic")
The real question isn't HTTP access — it's connecting to APIs you never pre-integrated, and shaping them for the agent's budget.
| Capability | Liquid | MCP server | Composio | DIY |
|---|---|---|---|---|
| Connect to any API on the fly (no pre-build) | ✓ | ✗ | ✗ | ~ |
| Pre-mapped API catalog | ✓ | ~ | ✓ | ✗ |
| Managed auth / OAuth handled for you | ~ | ~ | ✓ | ✗ |
| Token-aware search / aggregate (server-side) | ✓ | ✗ | ✗ | ✗ |
| Cross-API output normalization | ✓ | ✗ | ~ | ✗ |
| Structured recovery (next_action) | ✓ | ✗ | ✗ | ✗ |
| Deterministic, reproducible runtime | ✓ | ~ | ~ | ✓ |
| Self-healing on schema drift | ✓ | ✗ | ✗ | ✗ |
| Open source | ✓ | ~ | ✓ | n/a |
Liquid auto-discovers any API on the fly — its 2,500+ pre-mapped catalog and Composio's 500+ managed-auth integrations are complementary, not the same axis. Per-API MCP servers cover one API each. On managed auth, Liquid already auto-refreshes OAuth2 tokens and stores credentials encrypted per-tenant — you register the OAuth app once (bring your own client_id/secret); hosted "Connect with…" consent flows are on the roadmap. Competitor data: composio.dev, May 2026.
Use the transport that fits your agent. Same transformation layer, same adapters, same catalog.
pip install liquid-api. Async-first, type-hinted, framework-native via to_tools().
from liquid import Liquid
adapter = await liquid.get_or_create(url, target_model=...)
tools = adapter.to_tools("anthropic")
Model Context Protocol, stdio transport. Point it at the hosted API; your agent connects to any API by URL.
liquid_connect liquid_fetch liquid_query
Language-agnostic. Same transformation layer, swagger docs at /docs.
POST /v1/connect POST /v1/fetch POST /v1/query
No logos to wave yet — instead, everything you'd want to check is open and reproducible.
Don't take our word for it — read the code and reproduce the benchmarks yourself.
Report a security issue · see what we ship · talk to the founder
Point Liquid at any API and ship. Start free, or lock in lifetime founder access.