Loop exposes a clean REST API at api.stayinloop.dev/v1. Call it with requests or httpx, drop the OpenAPI spec into LangChain or the OpenAI SDK, or point an MCP-capable agent at stayinloop.dev/mcp. No key required in the free tier.
import requests BASE = "https://api.stayinloop.dev/v1" # search results = requests.get( f"{BASE}/search", params={"q": "quiet vegan restaurant", "location": "Kreuzberg, Berlin"}, ).json()["results"] top = results[0] print(top["name"], top["availability"]["status"]) # get full details + result_token details = requests.get(f"{BASE}/details/{top['result_id']}").json() # verify a claim live obs = requests.get( f"{BASE}/verify/{top['result_id']}", params={"claim": "open tonight"}, ).json() # report outcome (mutates confidence) resp = requests.post( f"{BASE}/report", json={"result_token": details["result_token"], "outcome": "correct"}, ).json() print(resp["new_confidence"])
Fetch the OpenAPI spec and convert it to OpenAI tool definitions. The model can then call search, get_details, verify, and report natively.
import json import requests from openai import OpenAI client = OpenAI() BASE = "https://api.stayinloop.dev/v1" # load Loop's tool definitions from the OpenAPI spec spec = requests.get(f"{BASE}/openapi.json").json() # convert to OpenAI tool format (simplified — adapt to your schema transformer) tools = [ { "type": "function", "function": { "name": path.strip("/").replace("/", "_"), "description": info.get("get", info.get("post", {})).get("summary", ""), "parameters": {"type": "object", "properties": {}}, }, } for path, info in spec["paths"].items() ] response = client.chat.completions.create( model="gpt-4o", tools=tools, messages=[{"role": "user", "content": "Find a vegan restaurant open now in Kreuzberg"}], )
Use httpx.AsyncClient to fan out get_details and verify in parallel — useful in FastAPI routes or async agent pipelines.
import asyncio import httpx BASE = "https://api.stayinloop.dev/v1" async def find_and_verify(query: str, location: str) -> dict: async with httpx.AsyncClient() as client: results = (await client.get( f"{BASE}/search", params={"q": query, "location": location}, )).json()["results"] if not results: return {"error": "no results"} top = results[0] details, obs = await asyncio.gather( client.get(f"{BASE}/details/{top['result_id']}"), client.get(f"{BASE}/verify/{top['result_id']}", params={"claim": "open now"}), ) return {**details.json(), "observation": obs.json()} result = asyncio.run(find_and_verify("vegan table for 4", "Kreuzberg, Berlin")) print(result["name"], result["observation"]["observed_at"])
Authorization: Bearer sk_live_… as a header or append ?key=sk_live_… to any URL.