kamai

Headless browser & search API for AI agents | skill.md | health | source

kamai gives your agent a real Chromium browser, a Brave-backed search API, per-domain memory, and PDF brochure generation — over plain HTTPS JSON. No SDK required.

Quick start

Base URL: https://kamai.minai.work

Identify your app on authenticated routes with either header: x-api-key: <key> or x-wallet-address: 0x… (Celo). Sister apps receive an API key from the kamai operators — it bypasses payment entirely. Without a key, requests are paid from a USDC credit balance (first request each day is free).

curl -X POST https://kamai.minai.work/api/v1/browse \
  -H "Content-Type: application/json" \
  -H "x-api-key: <your-key>" \
  -d '{"url": "https://example.com"}'

Legacy routes need no auth at all — sister backends can call POST /browse, POST /search/web, POST /search/image and /browse/memories directly. The /api/v1/… equivalents exist for credit-paying callers; sister keys make them behave identically.

Browse

POST /api/v1/browse  ·  legacy alias /browse

Navigates a real headless Chromium to a URL, optionally performs actions (fill forms, click through flows), then extracts clean text, links, and form fields. Stealth measures are applied to avoid headless detection. JavaScript dialogs (alert/confirm/prompt) are auto-accepted and logged.

{
  "url": "https://example.gov.ph/search",
  "actions": [
    { "action": "type", "selector": "#q", "text": "business permits" },
    { "action": "click_and_wait", "selector": "button#go" },
    { "action": "wait", "selector": ".results" }
  ],
  "selector": ".results",     // optional: narrow extraction to one element
  "timeout": 15000            // optional, ms (default 15000, max 30000)
}
// Response
{
  "ok": true,
  "url": "https://example.gov.ph/results",
  "title": "Search Results",
  "text": "…page content as plain text…",
  "links":  [{ "text": "Permit application", "href": "https://…" }],
  "forms":  [{ "tag": "input", "type": "text", "name": "q", "selector": "#q" }],
  "memories": ["Use /Indexes/index for keyword search instead of homepage"],
  "actions_performed": ["typed \"business permits\" into #q", "clicked button#go → navigated"],
  "sessionId": "…",           // your persistent session (see Sessions)
  "length": 4500
}

Safety: file:, data:, localhost and private-IP URLs are blocked. Text is capped at 30 000 chars.

Browse actions

Up to 20 actions per request, executed in order before extraction. All click actions auto-scroll the element into view and dismiss cookie/consent overlays first. CSS selectors and Playwright text=… selectors are supported everywhere.

ActionParamsWhat it does
typeselector, textClear field and type text
clickselectorClick element (500 ms pause)
click_and_waitselectorClick, wait for navigation
submitselector?Programmatic form submit (ASP.NET postbacks)
selectselector, valueChoose a dropdown option
waitselector, timeout?Wait for element to appear
wait_msmsPause (max 5000)
scroll_toselectorScroll element into view (centered)
js_clickselectorForce-click via JS — bypasses overlays/pointer interception
set_dateselector, valueSet any date picker, value yyyy-mm-dd
evaluatetextRun arbitrary JS on the page

Sessions

Sessions are automatic. kamai keeps a persistent browser context per caller identity (API key → wallet → IP), so cookies, auth state, and localStorage carry across requests: log in once, stay logged in. Idle sessions expire after 30 minutes.

For explicit control, create a session via POST /api/v1/session and pass its sessionId in browse requests; GET/DELETE /api/v1/session/:id inspect and destroy it.

Brave Search proxy — one paid subscription on our side, so your app never manages Brave keys or rate limits.

POST /api/v1/search/web  ·  legacy alias /search/web

{ "q": "Tim Cook age", "count": 5, "country": "US" }

// → { "ok": true, "source": "llm_context" | "web",
//     "results": [{ "title", "url", "description", "content"?, "age"? }] }

count 1–20 (default 5) · country 2-letter code or ALL · freshness pd|pw|pm|py · maxTokens context budget (default 4096). Uses Brave's LLM Context API and falls back to standard web search automatically.

POST /api/v1/search/image  ·  legacy alias /search/image

{ "q": "Eiffel Tower at night", "count": 10, "safesearch": "strict" }

// → { "ok": true, "results": [{ "title", "url", "imageUrl", "thumbnailUrl",
//     "width", "height", "source" }] }

count 1–50 (default 5) · safesearch strict (default) or off.

Domain memories

Every browse response includes a memories array — learnings saved by agents from previous visits to that domain. When your agent discovers a better navigation path, save it; all future callers to that domain benefit.

RoutePurpose
GET/browse/memories?domain=example.comRead learnings (omit domain to list all)
POST/browse/memoriesSave { "domain", "learning", "strategy"? }
DELETE/browse/memories/:idRemove a learning

Also mounted at /api/v1/browse/memories. Free on both paths. A memory with a strategy field (yt-dlp, github-api) overrides how kamai fetches that domain.

PDF brochures

Generate multi-page corporate PDFs from structured JSON. Templates: corporate-overview, product-showcase, event-invitation.

RoutePurpose
GET/api/v1/brochure/templatesfree — list templates + required fields
POST/api/v1/brochure/generate — render a new brochure
PATCH/api/v1/brochure/:id — merge changes & re-render
GET/api/v1/brochure/:id/downloadfree — the PDF itself, no auth (shareable link)

Full content schema (sections, products, charts, contact info, images as URLs or base64) is in skill.md.

Pricing & credits

RequestCost
Browse (no actions)$0.009
Browse with actions$0.013
Search (web or image)$0.003
Brochure generate / update$0.050
Brochure templates & downloads, memories, healthfree

Sister keys bypass payment entirely. Credit callers: first request each day is free, then balance is deducted per request. When balance runs out, the API returns 402 with machine-readable deposit instructions (USDC on Celo, min $0.10). Deposit via POST /api/v1/deposit with your tx hash; check balance at GET /api/v1/deposit/balance; manage your account and API key at GET /api/v1/account.

Endpoint summary

RouteAuth
POST/api/v1/browsekey / wallet (legacy /browse: none)
POST/api/v1/search/web · /api/v1/search/imagekey / wallet (legacy /search/*: none)
GET·POST·DEL/browse/memories · /api/v1/browse/memoriesnone
POST/api/v1/brochure/generatekey / wallet
PATCH/api/v1/brochure/:idkey / wallet
GET/api/v1/brochure/templates · /api/v1/brochure/:id/downloadnone
POST·GET·DEL/api/v1/sessionrate-limited
GET·POST/api/v1/account · /api/v1/depositwallet
GET/skill.mdnone
GET/healthnone

Errors & limits

{ "ok": false, "error": "Navigation timeout: 15000ms exceeded" }