Reference

API

Two endpoints. The request shape mirrors what most agent code already speaks, so adopting it is usually a base URL change.

Authentication

Send your key either way. Both work, on every endpoint.

authorization: Bearer twl_...
x-api-key: twl_...

Keys carry one of two scopes. A search key can spend quota and nothing else, which is what you deploy into agents and containers. An admin key can also mint and revoke keys and read usage. The raw key is shown once, at creation; only its hash is stored, so it cannot be recovered.

{
  "query": "what changed in the EU AI act",   // required
  "search_depth": "basic",                     // "basic" | "advanced"
  "topic": "general",                          // "general" | "news"
  "max_results": 5,
  "include_answer": false,
  "include_raw_content": false,
  "include_domains": [],
  "exclude_domains": [],
  "time_range": "week"                         // day | week | month | year
}

Depth is the cost dial. basic returns provider snippets and fetches no pages. advanced fetches every result, extracts clean Markdown, and ranks passages. That is roughly an order of magnitude in both latency and cost. Asking for an answer implies the full pipeline, because there is nothing to answer from otherwise.

Topic selects the providers. general uses Bing and DuckDuckGo; news uses Google News and Yahoo News.

Response

{
  "query": "...",
  "answer": "The Act entered into force ...",   // null unless include_answer
  "answer_citations": ["https://..."],
  "results": [
    {
      "title": "...",
      "url": "https://example.com/article",
      "content": "# Heading\n\nClean markdown ...",
      "score": 0.03175,
      "published_date": "Tue, 12 Aug 2026 09:14:00 GMT",
      "providers": ["bing", "duckduckgo"],
      "fetched": true,
      "fetch_error": null
    }
  ],
  "providers": [
    { "provider": "bing", "status": "ok", "resultCount": 10, "elapsedMs": 304 },
    { "provider": "duckduckgo", "status": "circuit_open", "resultCount": 0,
      "error": "breaker open until ...", "elapsedMs": 0 }
  ],
  "response_time": 3.1
}

Always read providers

Three of the four sources are HTML scrapers. This array is how you tell a complete answer from a degraded one.

statusMeaning
okReturned results.
failedTried and failed. error says why.
circuit_openOut of rotation after repeated failures.
disabledSwitched off for your org.
skippedCannot serve this topic.

An empty results array only ever means the web had nothing to say. If every provider failed you get a 502, never a 200 with nothing in it.

The providers field on each result is a quality signal in its own right: a URL listed by two engines was ranked independently by both. Results are fused by rank, so agreement lifts a page above any single provider's favourite.

POST /v1/extract

The same pipeline without the retrieval stage, for URLs you already have.

{ "urls": ["https://example.com/a", "https://example.com/b"] }
{
  "results": [
    { "url": "...", "title": "...", "content": "# ...", "source": "fetch" }
  ],
  "failed": [
    { "url": "...", "error": "disallowed by robots.txt" }
  ],
  "response_time": 1.2
}

URLs are canonicalised and deduplicated before anything is charged, so the same page with three different tracking parameters costs one extraction. Billing is per URL, and URLs that produce nothing are refunded. If nothing at all could be extracted you get a 502, because an empty array would read as "these pages are blank".

Errors

StatusWhen
400Malformed request. details carries the field errors. Fail loud; this is a bug in the caller, not an empty result.
401Missing, unknown, or revoked key.
403Valid key, insufficient scope.
429Rate limit or quota. Rate limits carry retry-after.
502Every provider failed, or nothing could be extracted.
503A required capability is not configured.

A missing capability returns 503 naming it rather than quietly omitting it. A response that looks successful while leaving out the thing you asked for sends you debugging the wrong layer.

Notes for agent authors

Base URL

https://api.trawlia.co