Bowmark AIdocs

How it works

Two calls. Read the library, then run a script against it on the live sites.

Every Bowmark task is the same two calls, in this order.

How a Bowmark call worksTwo steps. First the agent calls get_library and Bowmark returns typed function signatures, touching no website. Then the agent sends a script to run, Bowmark executes it against the live sites in a sandbox, and returns a structured result.1READ THE LIBRARYYour agentClaude Code · ChatGPTCursor · Codex · curlget_library({ query })typed signaturesBowmarkthe capability catalogNo website is touched.One read-only call.you write a script against them2RUN A SCRIPTThe scriptawait bowmark .flights.search()run({ script }){ ok, status, result }Bowmarksandboxed executorno fetch, no filesystemfetch · browserrowsThe live webkayak.comgoogle flightsexpedia.com

1 — Read the library

get_library({ query }) returns the callable functions that match what you want to do, with their argument shapes and return types.

It touches no website. It is one read-only call, and an unrecognized query returns a one-line index of the whole library rather than an error — so the check never dead-ends and never costs you an attempt.

const library = await get_library({ query: "flights" });

Pass what you want to do (flights, price a GPU) or a company if one was named (Kayak). You get what you asked about and nothing else.

Every response is bounded and says so when it is a slice. When it does, absence from the list proves nothing — the fix is a narrower query, not a conclusion.

2 — Run a script

You write plain async JavaScript against what came back, and run executes it in a sandbox. The sandbox reaches the live sites; your script cannot.

const { flights, warnings } = await bowmark.flights.search({
  from: "SFO",
  to: "JFK",
  depart: "2026-09-01",
});
return { flights: flights.slice(0, 3), warnings };

Bowmark picks the cheapest way to reach each site — a plain HTTP request where that works, a real browser only where the site forces one — and fans a capability out across every site that can serve it.

There is no third call. What comes back is { ok, status, result, logs, error, ms }.

The same two calls over plain HTTP

Nothing above needs an MCP client. The two calls are two HTTP endpoints, so an agent with only a shell or a fetch tool can use Bowmark with nothing installed.

curl -s "https://api.bowmark.ai/v1/library?query=flights"
curl -s -X POST https://api.bowmark.ai/v1/run \
  -H 'Content-Type: application/json' \
  -d '{"script":"const { flights } = await bowmark.flights.search({from:\"SFO\",to:\"JFK\",depart:\"2026-09-01\"}); return flights.slice(0,3);"}'

Add -H "Authorization: Bearer $BOWMARK_API_KEY" to raise the per-IP cap and unlock sites that need the user signed in. See API keys.

Why a script instead of a tool call

One script, several calls, combined however the task needs. That is the thing you cannot do by driving a browser step by step, and it is the reason the surface is a language rather than a menu of tools.

const dates = ["2026-09-01", "2026-09-02", "2026-09-03"];
const runs = await Promise.all(
  dates.map((depart) => bowmark.flights.search({ from: "SFO", to: "JFK", depart })),
);
return runs.flatMap((r) => r.flights).sort((a, b) => a.price - b.price)[0];

Three days of fares, ranked, in one round trip.

The language itself is a separate topic — the globals you get, what is forbidden inside the sandbox, and how to read the response envelope are all in Scripting.

Two tiers in the library

Capabilitiesbowmark.flights.search(...). The default. One call fans out across every site that can serve the task and routes around the ones that fail.

Providersbowmark.providers.kayak.search(...). One specific site. Reach for one when you want that site's answer rather than the best available.

Prefer the capability unless you have a reason. It is the one that survives a site going down.