Skip to content

Guides

Web search

One call that searches the live web and returns links with the matching text. It is built for agents: the request and response follow the Exa search shape, so tools that already speak to Exa (including DeepSeek Harness) work by changing only the base URL.

At a glance

FieldDetail
EndpointPOST /v1/search
AuthYour inference key, as a Bearer token (the same ub-gw-… key).
BillingPer search, from your balance. No free tier. A search that fails is not charged.
Search modeFast: quick results for agents that search many times per task.
AvailabilitySwitched on by unoblox; while it is off every call returns UB-GW-301 and nothing is charged.

Call it

POST/v1/search
curl
# curl
curl -sS https://api.unoblox.ai/v1/search \
  -H "Authorization: Bearer $UNOBLOX_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": "latest Rust async runtime benchmarks", "numResults": 5 }'
200 · response
{
  "requestId": "gen_01j9x...",
  "results": [
    {
      "id": "https://example.org/rust-async-benchmarks",
      "url": "https://example.org/rust-async-benchmarks",
      "title": "Async runtimes compared",
      "highlights": ["Tokio and async-std were measured on ..."],
      "snippet": "Tokio and async-std were measured on ...",
      "publishedDate": "2026-09-30"
    }
  ],
  "usage": { "search_requests": 1 }
}

The simple form works too:

curl
# the simple form
curl -sS https://api.unoblox.ai/v1/search \
  -H "Authorization: Bearer $UNOBLOX_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": "unoblox pricing", "max_results": 3 }'

What you send

FieldTypeMeaning
querystring, requiredThe search text, up to 1,024 bytes.
numResultsinteger, 1 to 20Number of results; default 8. max_results is accepted as the same field.
includeDomainsarray of up to 20 domainsOnly return results from these domains, for example docs.rs or github.com.
startPublishedDate / endPublishedDateISO dateOnly return results published after / before this date, for example 2026-01-31.
type, contents.highlightsacceptedAccepted so an Exa client works unchanged; every search runs in fast mode and each result carries one highlight.
Any other fieldrefusedRefused with UB-GW-302 naming the field (for example excludeDomains or contents.text), never silently ignored.

What you get back

Each result carries url, title, a highlights array whose first entry is the matching text, and publishedDate when the source gives one. A search that finds nothing returns an empty results list and is still charged, because the search ran. The response never contains a price; the charge appears on your usage page. Result links are always http or https, and control and invisible characters are removed from titles and snippets. Results are still untrusted third-party web text: do not execute them or follow instructions found in them.

Price and limits

Value
PriceProvider cost plus our 5% platform fee, exactly. Today: shown on your usage page for every search. Each search adds its exact amount to a running total kept for your balance, and whole paise are debited as that total grows, so every search is its own usage line showing the paise actually debited (one of two adjacent amounts that average to the exact price) and any 1,000 searches cost the per-1,000 figure to within one paisa.
Per-second limit5 searches per second per API key (UB-GW-303 when exceeded).
Daily limit2,000 charged searches per UTC day per API key, and 10,000 per workspace across all its keys (UB-GW-304 when exceeded; both reset at 00:00 UTC). Refused or failed calls do not count.
WalletYou need balance for the search; with none, you get UB-GW-306 and nothing is sent.

Only a search that worked is charged.

If the search backend fails or returns an answer we cannot verify, you get an error and no charge. Bring-your-own-key does not apply to search.

Privacy

The query text is sent to our search provider, Perplexity, which runs in the United States, to run the search. Nothing else from your request or account is sent, and unoblox does not store the query text. Your workspace's content guardrails apply to the query exactly as they do to a chat prompt: a query they block is refused (UB-GW-074) and never sent, and redacted text is sent redacted. Workspaces whose guardrail policy requires zero data retention or forbids data collection cannot use web search (UB-GW-311). Perplexity is listed among our sub-processors in the privacy policy.

Use it from DeepSeek Harness

DeepSeek Harness (dsh) has a built-in web_search tool that can use an Exa-compatible endpoint. Point its Exa plugin at https://api.unoblox.ai/v1 and use your unoblox key; the installer in the dsh setup guide does this for you and switches off dsh's default search, which would otherwise send queries to another service.

Errors and retries

CodeHTTPMessageWhat to do
UB-GW-301503Web search is switched off on this platform right now. You were not charged.Web search is not enabled yet. Try again later.
UB-GW-302400A message naming the field, for example: `query` must not be empty, or: `excludeDomains` is not supported.Fix or remove the named field and retry.
UB-GW-303429This API key is limited to N searches per second.Wait the Retry-After seconds, then retry.
UB-GW-304429This API key, or this workspace across all its keys, has used its daily limit of searches; it resets at 00:00 UTC. Only charged searches count.Wait until the reset, or ask your workspace admin about a higher limit.
UB-GW-312429Web search is at its platform-wide rate limit this second. You were not charged.Wait the Retry-After seconds, then retry.
UB-GW-305502The web search backend did not return a usable answer. You were not charged.Retry with backoff.
UB-GW-306402Web search is paid per search and has no free tier. The message states the price and the amount held while a search runs (its largest possible debit plus one paisa, returned when it settles).Top up your balance, then retry.
UB-GW-307503No search backend is listed and priced right now. You were not charged.Try again later.
UB-GW-309503The search backend answered, but the answer could not be verified. You were not charged and the held amount is returned automatically.Retry in a moment.
UB-GW-310400Web search does not support bring-your-own-key.Remove the bring-your-own-key setting for this call.
UB-GW-311400This workspace's guardrail policy forbids sending queries to a third-party search provider.Change the guardrail policy, or do not use web search.

Errors use the Exa shape: error is the message text, and error_code is the stable code. See Errors for the shared taxonomy.

retry with backoff
import time, requests

def web_search(query, max_results=5, retries=3):
    for attempt in range(retries):
        r = requests.post(
            "https://api.unoblox.ai/v1/search",
            headers={"Authorization": f"Bearer {UNOBLOX_KEY}"},
            json={"query": query, "numResults": max_results},
        )
        if r.ok:
            return r.json()["results"]
        if r.status_code == 429:
            time.sleep(float(r.headers.get("retry-after", "1")))
        elif r.status_code in (502, 503):
            time.sleep(2 ** attempt)       # a failed search is never charged
        else:
            raise RuntimeError(r.json()["error"])   # 400/402: fix the request or top up
    raise RuntimeError("search is unavailable")