API integrator

An agent that calls live REST APIs with a single httpx-backed tool and reasons over the responses in a natural ReAct loop.


What it does

This example gives an agent one general-purpose tool, call_api, that performs an HTTP request with httpx and returns the raw response as text. The agent decides which endpoint to hit, inspects what comes back, and calls the tool again if it needs to follow a link or fetch a related resource. That back-and-forth is the ReAct loop you get for free from the agentic run loop — you don't orchestrate it, the model does.

It shows two core concepts: tools (turning a plain Python function into something the model can call) and agents (the loop that lets the model act, observe, and act again until it can answer).

Keep tools simple

A single low-level tool like call_api is often more flexible than a dozen endpoint-specific ones. The model composes calls itself, so you write less glue and the agent handles APIs you never hard-coded.

The agent

The tool takes three string arguments — url, method, and a JSON body — so the schema the model sees stays flat and easy to fill in. The docstring and type hints are turned into the tool schema automatically, so the model knows what each argument is for.

api_integrator.py
import httpx
 
from agentroute import Agent
 
agent = Agent(
    name="api-integrator",
    model="claude-sonnet-4",
    instructions=(
        "You call REST APIs to answer questions. Use the call_api tool to "
        "fetch data, inspect the JSON that comes back, and make follow-up "
        "calls when you need related resources. Summarize the result "
        "clearly and cite the fields you used."
    ),
)
 
 
@agent.tool
def call_api(url: str, method: str = "GET", body: str = "{}") -> str:
    """Make an HTTP request to a REST API and return the response body.
 
    Args:
        url: The full URL to request, including https://.
        method: HTTP method, e.g. GET, POST, PUT, DELETE.
        body: JSON-encoded request body, used for POST/PUT/PATCH.
    """
    payload = body.strip()
    response = httpx.request(
        method.upper(),
        url,
        content=payload.encode() if payload and payload != "{}" else None,
        headers={"Content-Type": "application/json", "Accept": "application/json"},
        timeout=30.0,
    )
    return f"HTTP {response.status_code}\n\n{response.text}"
 
 
if __name__ == "__main__":
    result = agent.run(
        "Fetch https://api.github.com/repos/python/cpython and summarize "
        "the repo: stars, open issues, primary language, and the description."
    )
    print(result)

Because call_api is a synchronous function, the run loop offloads it to a worker thread automatically, so a slow request never blocks the event loop. The tool returns the status line plus the body so the model can react to non-200 responses (rate limits, 404s) and decide whether to retry or change course.

Run it

pip install agentroute httpx
export AGENTROUTE_API_KEY="sk-or-..."
python api_integrator.py

The agent will call call_api with the GitHub URL, read the JSON, and produce a summary. Point it at any public REST API — try a follow-up question like "now list the five most recently updated repos for that org" and watch it chain a second call from the organization field it just read.

Outbound requests run real code

call_api will hit whatever URL the model chooses. Keep the agent pointed at endpoints you trust, set sensible timeouts (as above), and add needs_approval=True to the @agent.tool decorator if you want a human to confirm each call before it fires. Hosted MCP and managed browser tooling for richer integrations are forthcoming — see the platform roadmap.

Authenticated APIs

To call an API that needs a key, read it from the environment inside the tool rather than exposing it to the model. The model never sees the header — it only sees the url it asked for.

import os
 
import httpx
 
from agentroute import Agent
 
agent = Agent(name="api-integrator", model="claude-sonnet-4")
 
 
@agent.tool
def call_api(url: str, method: str = "GET", body: str = "{}") -> str:
    """Call a REST API and return the response body. Auth is added automatically."""
    payload = body.strip()
    response = httpx.request(
        method.upper(),
        url,
        content=payload.encode() if payload and payload != "{}" else None,
        headers={
            "Authorization": f"Bearer {os.environ['SERVICE_TOKEN']}",
            "Content-Type": "application/json",
        },
        timeout=30.0,
    )
    return f"HTTP {response.status_code}\n\n{response.text}"

Concepts used

  • Tools — the @agent.tool decorator and how schemas are derived from type hints and docstrings.
  • Agents — the run loop that turns one tool into ReAct-style multi-step behavior.
  • Agent and tool — the API reference for the pieces used above.