orbitadocs
Benchmarks llms.txt Sign inGet a key

ORBITA API / v1

One call.
Everything you were going to fetch anyway.

Orbita is a source and context API built for agents rather than a general chatbot. Five fixed depth modes return ranked sources; an optional Auto router resolves a question to one of those modes. An optional Context layer then returns either a synthesized brief or an evidence package assembled from original source blocks.

Private beta. These pages describe five fixed depth modes plus optional Auto and source-grounded Context. The local prototype now uses the real server-side account, API-key and credit ledger; file:// pages alone retain a clearly labelled preview. Create an account to start with $1 credit.

What Orbita is

There is one endpoint. You send a question in natural language; you get back the pages that answer it, ranked, with their text. The fixed modes are Fast, Standard, Pro, Deep and Ultra; mode: "auto" selects one of them without exposing a sixth candidate budget.

What makes that worth a separate product is what is not in the normal response path: no second call to fetch page content, and no separate date-extraction call. When a trustworthy publication date cannot be found, published is null rather than an invented crawl date. If you enable Context, Evidence mode still returns original blocks; Summary mode is optional and review-gated.

100
ranked sources in Ultra, with smaller result budgets for faster modes.
1
round trip. Content and citations arrive with results; dates are attached when available.
per 1 000 Fast searches. New Search scales to Ultra at ; Compact is .
4.56 s
prototype p50 end-to-end in the 2026-09-09 test; this is not a production SLA.

What it is not

Orbita is not a general chatbot, not a crawler you point at a URL, and not a Google proxy. It can optionally build a compact context or an evidence package, but it does not pretend that a generated brief is the source: Evidence mode keeps source blocks, IDs, dates and citations available for verification. If you want an essay with footnotes, ask your own model; Orbita gives it grounded material and stays out of the way.

Orbita Gravity

Gravity is Orbita’s evidence-quality technology. It reduces irrelevant page material while keeping the useful source material verifiable. Customers receive cleaner context, source links and citation-ready evidence; the internal extraction and ranking implementation is intentionally not public.

Public boundary. We publish the behavior clients can rely on, measured outcomes and known limits. Model choices, internal stages, scoring rules, thresholds and infrastructure topology remain proprietary.

Measured outcome

71.3%
less irrelevant visible page text in the frozen test.
83.5%
exact control fields retained from ordinary pages.
93.5%
exact fields retained across the full supported-source test.
91.0%
exact evidence retained in a bounded response.

Frozen 2026-09-12 run: five public Ukrainian admissions sites and ten pages. Exact-match scoring was used. This is an Orbita before/after measurement, not a head-to-head extraction benchmark.

Public competitor data

ProductPublished extraction facts
ExaContents costs $1 per 1,000 pages for each requested content type. Its own 250-URL evaluation reports 89.3 accuracy, 96.7 code recall and 91.9 table recall.
TavilyUp to 20 URLs per call; query-focused output supports 1–5 chunks of at most 500 characters. At PAYG rates, Basic and Advanced equal about $1.60 and $3.20 per 1,000 successful URLs.
LinkupFetch accepts one URL per call and costs $1 per 1,000 pages without JavaScript or $5 per 1,000 with JavaScript. Errors are not charged.
FirecrawlBasic scrape costs one credit per page. Annual self-serve tiers imply roughly $0.60–$3.20 per 1,000 pages; its own 1,000-URL evaluation reports 96% success and 3.387 s p95.

Official references checked 2026-09-13: Exa pricing and vendor evaluation; Tavily Extract and credits; Linkup pricing; Firecrawl pricing and vendor evaluation. Vendor-run quality figures are not mixed with Orbita’s measurement.

Quickstart

Three things: a key, a request, a response. If you have curl you are ninety seconds away.

  1. Get a key.

    Create an account and press New key; it starts with orb_live_. It is shown in full exactly once, so copy it then. Keep it server-side — a key in a browser bundle is a key someone else is now using.

  2. Put it in the environment.
    shell
    export ORBITA_API_KEY="orb_live_your_key_here"
  3. Make the call.
    curl https://api.orbita.dev/v1/search \
      -H "Authorization: Bearer $ORBITA_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "biomimicry in contemporary architecture",
        "limit": 10,
        "content": "text"
      }'

You will get an object with results, usage and took_ms. The whole shape is in Response.

Runnable variants for cURL, Python, TypeScript and Go are kept in prototype/examples/phase2-search.*; they use the local session-token contract and do not contain production secrets.

Authentication

The public Search API uses a bearer key on every request; it does not accept signed URLs or dashboard cookies.

http
Authorization: Bearer orb_live_...

Keys are scoped to a project and can be rotated without downtime: create the new one, deploy it, delete the old one. A deleted key stops working immediately — there is no grace window, so do it in that order.

The dashboard itself is different: signup/signin create an opaque server session in an HttpOnly; SameSite=Strict cookie, and every state-changing browser request carries a CSRF token. Session cookies are never valid as corpus-admin credentials.

Query text is not account history. Orbita processes it for the current call but does not retain it in usage events or use customer queries/results to train Orbita models. The account ledger keeps status, latency, result count, resolved mode and cost for at most 90 days.
Never ship a key to a browser or a mobile binary. Anything the user's device can read, the user can read. Put the call behind your own endpoint. If a key does leak, delete it first and investigate second.

Parameters

FieldTypeDefaultWhat it does
query requiredstringA question or a description in natural language. Write it the way you would ask a colleague; keyword soup ranks worse here, not better. Hard limit 2 000 characters.
limitintegermode maximumHow many results to return, up to the selected mode's result budget. Asking for fewer does not change that mode's price.
contentenum"text""text" — clean page text. "none" — titles and URLs only, with a smaller response; its production latency effect is not yet measured. "markdown" — text with headings and lists preserved.
max_charsinteger2000Characters of page text per result, 200–20 000. This is the single biggest lever on your token bill: 25 results at 2 000 characters is roughly 12 k tokens, at 20 000 it is 120 k.
modeenum"auto"Five fixed modes: Fast 20→5, Standard 100→10, Pro 200→25, Deep 300→50, Ultra 500→100. Auto resolves to one fixed mode and reports why.
max_modeenum"ultra"Auto ceiling. It never selects a deeper mode than this.
max_cost_usdnumberPer-request USD ceiling in the same unit as usage.cost_usd. Auto downgrades only within max_mode; a request fails if no mode fits.
max_resultsinteger100Client ceiling. The resolved mode and limit are both capped by it.
langstring[]autoISO 639-1 codes to prefer, e.g. ["uk","en"]. Left out, the language of the query decides. This is a preference, not a filter: a decisive English source still outranks a weak Ukrainian one.
published_after
published_before
dateYYYY-MM-DD. Filters on the publication date, not the crawl date. Pages we could not date are excluded when either bound is set — say so out loud rather than let a filter silently drop a third of the web.
domains.includestring[]Up to 50 hosts. Subdomains are included: bbc.co.uk also matches news.bbc.co.uk.
domains.excludestring[]Up to 50 hosts to drop. Applied after ranking, so excluding a domain promotes what was behind it rather than shortening the list.
highlightsinteger00–5 passages per result that most directly answer the query, with character offsets into text. Use these for citations instead of asking the model to find the quote again.
timeout_msinteger15000500–30 000. On timeout you get 504 and are not billed. The staging default was raised after a measured cold-start exceeded 8 seconds; set it below your agent's own deadline.
linksenum"relevant""none", relevant discovered links, or "all". Relevant links are classified as official, docs, support, careers, social, phone or email where the source exposes them.
context.enabledbooleanfalseOptional Context/Compact layer. False keeps the normal retrieval behavior.
context.strategyenum"evidence"evidence has Ling select source-scoped IDs and the server reconstruct original blocks; summary asks inclusionai/ling-3.0-flash for a shorter synthesis and falls back to deterministic Evidence.
context.max_tokensinteger1000One of 500 / 1 000 / 2 000 / 4 000. This output ceiling is independent from the mode input maximum of 3 000 / 5 000 / 10 000 / 20 000 / 50 000 tokens. Input is not padded.
context.citations / datesbooleantrueControls citation IDs and publication/modified dates in the context package. Evidence text itself is never rewritten.
The parameter we deliberately do not have: a relevance threshold. Scores are comparable within one response and meaningless across two, so a fixed cut-off would silently return nothing on a hard query. Take the top n and let your model decide what is useful.

Response

200 OK
{
  "id": "req_01JZQ8F3M2K9",
  "query": {
    "text": "how Ukrainian grain export corridors changed in 2026",
    "language": "en"
  },
  "requested_mode": "auto",
  "resolved_mode": "pro",
  "selection_reason": "multi_source_current_events",
  "results": [
    {
      "url": "https://www.reuters.com/markets/commodities/…",
      "title": "Black Sea corridor volumes recover to pre-war levels",
      "site": "reuters.com",
      "published": "2026-06-18",
      "retrieved": "2026-08-06T04:12:51Z",
      "language": "en",
      "score": 0.914,
      "text": "Grain shipments through the Black Sea corridor …",
      "highlights": [
        { "text": "volumes reached 5.2 million tonnes in May", "start": 412, "end": 454 }
      ]
    }
  ],
  "context": { "enabled": true, "strategy": "evidence", "input_tokens": 1470, "output_tokens": 1470, "max_tokens": 2000 },
  "usage": { "searches": 1, "results": 25, "context_input_tokens": 1470, "context_output_tokens": 1470, "cost_usd": 0.00799 },
  "took_ms": 138
}
FieldTypeNotes
idstringRequest id. Quote it when you report a problem; it is how we find your call in the logs.
query.languagestringWhat language we decided the question was in. Worth logging — a wrong guess here explains most surprising result sets.
results[].publisheddate | nullnull when the page carries no trustworthy date. We would rather admit that than invent one from the crawl time, which is what a date on every single result usually means.
results[].retrieveddatetimeWhen we last fetched the page. The gap between this and published tells you how stale the text may be.
results[].scorefloat0–1, comparable within this response only. Do not persist it, do not threshold on it, do not compare it across queries.
results[].textstring | nullPage text, boilerplate removed, truncated to max_chars on a word boundary. null when content: "none".
results[].highlightsarrayOffsets are into text, so text.slice(start, end) gives you the exact quote to cite.
usage.cost_usdfloatWhat this call actually cost, on the response. No end-of-month arithmetic to work out where the money went.
requested_mode / resolved_modestringAuto preserves what the client asked for and reports the fixed mode actually used.
selection_reasonstringStable router reason such as multi_source_current_events; it is a routing explanation, not a relevance score.
contextobject | nullOptional Summary or Evidence package. Evidence blocks are original source blocks and carry section_id, block_id and passage_id when citations are enabled.
usage.results, context_input_tokens, context_output_tokensintegerCustomer-visible result and optional Context usage counters.
took_msintegerServer-side time. Your wall clock will be this plus the round trip — see the reach map for what that is from where you are.

Query recipes

The failure mode we see most often is a query written for a keyword engine. Choose a fixed depth when you know the budget; use Auto when the client should choose.

RESEARCH A CONCEPT

"biomimicry architecture"

"buildings whose cooling systems copy termite mounds"

Describe the thing rather than naming the category. Pair with mode: "pro" and limit: 25.

COMPANY / CONTACT LOOKUP

mode: "fast", links: "relevant"

Ask for the official site, docs, support, careers, GitHub, social handles, email or phone. Orbita returns only links extracted from indexed source content.

TECHNICAL QUESTION

mode: "pro", context.strategy: "evidence"

Evidence mode returns raw blocks and stable IDs so the answering model can preserve code, specifications, numbers and negations.

NEWS BRIEFING

mode: "pro" or "deep", published_after

Use Pro for a focused briefing, Deep for many independent sources. Auto resolves current-events questions to a safe fixed mode.

BROAD / MAXIMUM RECALL

mode: "deep" or "ultra"

Deep covers broad research; Ultra is for due diligence and critical investigation when the client accepts the largest candidate and result budget.

COMPACT SUMMARY

context: { enabled: true, strategy: "summary", max_tokens: 1000 }

Summary is optional and review-gated. If the free model is unavailable or rate-limited, the response remains source-grounded through Evidence fallback.

FIND SOMETHING RECENT

published_after plus a question with no date in it

Do not write “in 2026” into the query — that ranks pages that mention 2026. The filter is what restricts time; the text is what describes the subject.

LOOK UP A FACT

mode: "fast", limit: 5, max_chars: 800

For error strings, version numbers and names, exact matching beats semantic search and costs you less context.

FEED AN AGENT LOOP

content: "none" first, then re-query the winners

When the model is going to discard most of what it reads, get titles first to reduce response size and model tokens, then fetch text for the two or three that survived.

Errors

Every failure returns the same envelope, with the HTTP status and a stable machine-readable type. Branch on type, never on the message — messages get reworded, types do not.

429 Too Many Requests
{
  "error": {
    "type": "rate_limited",
    "message": "20 requests per second exceeded on key orb_live_…f31c.",
    "retry_after": 0.4,
    "retryable": true,
    "request_id": "req_01JZQ8F3M2K9",
    "docs": "https://orbita.dev/docs#errors"
  }
}
StatustypeRetry?What to do
400invalid_requestnoA field is missing or the wrong shape. The message names the field. Fix the caller.
401invalid_keynoMissing, malformed or deleted key. Retrying will not create one.
402quota_exhaustednoPrepaid balance is gone. Top up; queued retries will only pile up.
413query_too_longnoOver 2 000 characters. Summarise the question before sending it — a 3 000-character query ranks worse anyway.
422unsupported_filternoA filter combination that cannot return anything, e.g. published_after later than published_before.
429rate_limitedyesWait retry_after seconds, then retry with jitter. Do not retry immediately in a loop; that is how you turn a spike into an outage.
500internalyesOurs. Retry twice with backoff, then surface it. Send us the request_id.
503capacityyesWe are shedding load. Back off harder than for a 500 — a second or more.
504timeoutyesYour timeout_ms elapsed. You are not billed. Either retry or degrade — for most agents, answering without search beats waiting twice.

Retry that will not make things worse

import random, time, httpx

RETRYABLE = {"rate_limited", "internal", "capacity", "timeout"}

def search(payload, attempts=3):
    for attempt in range(attempts):
        r = httpx.post(URL, headers=HEADERS, json=payload, timeout=30)
        if r.status_code < 400:
            return r.json()

        err = r.json().get("error", {})
        if err.get("type") not in RETRYABLE or attempt == attempts - 1:
            raise RuntimeError(f"{err.get('type')}: {err.get('message')}")

        # Honour retry_after when the server sent one; jitter either way, or a
        # fleet of workers will retry in lockstep and rebuild the same spike.
        wait = err.get("retry_after") or 2 ** attempt
        time.sleep(wait * (0.5 + random.random()))

Rate limits

Limits are per key, not per project, so you can give a noisy batch job its own key and keep it away from your live traffic.

PlanRequests / secondBurstConcurrent
Beta52010
Standard206040
Scale100300200
HigherAsk. We would rather raise your limit than have you shard across five keys.

Every response carries the current state, so you can pace yourself without waiting to be told off:

response headers
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 17
X-RateLimit-Reset: 0.31

Pricing

Five fixed depth modes plus optional Auto. New Search is per 1 000; Search + Compact is and includes a controlled context pass. Page content and citation highlights are included in every mode; publication dates are included when available, and a timeout costs nothing.

Orbita modeCandidates → resultsNew SearchSearch + CompactMax context for LFMBest for
Fast20 → 5Autocomplete and simple facts
Standard100 → 10Daily agents, chat, product search
Pro200 → 25Comparisons and evidence-heavy questions
Deep300 → 50Broad single-pass research
Ultra500 → 100Maximum recall

Launch pricing, updated 2026-09-13. Deep is a wider single-pass retrieval budget, not a multi-step research agent. Page text and citations are included; published is nullable. Context ceilings apply to Compact output for the selected mode.

Where the money actually goes. In the agent traces we have measured, search is around 22% of the bill and model tokens are the other 78%. Which means the lever that matters is not the price per search — it is how many searches and how many tokens an answer takes. That is why max_chars and content: "none" are documented as loudly as the price is.

Agent quickstart

If you are a coding agent reading this page, or you are pasting context into one, this is the block to take. It is self-contained: endpoint, auth, schema, limits, and the mistakes that cost the most.

ORBITA / INTEGRATION BRIEF
You are integrating the Orbita search API.

ENDPOINT   POST https://api.orbita.dev/v1/search
AUTH       Authorization: Bearer $ORBITA_API_KEY   (server-side only)
CONTENT    application/json

REQUEST
  query            string, required, <= 2000 chars, natural language
  mode             enum   auto | fast | standard | pro | deep | ultra, default auto
  max_mode         enum   fast | standard | pro | deep | ultra, default ultra
  max_cost_usd     number Per-request USD ceiling; same unit as usage.cost_usd
  max_results      int    1 to 100, client ceiling
  limit            int    1 to the resolved mode maximum
  content          enum   "text" | "markdown" | "none",  default "text"
  max_chars        int    200-20000, default 2000   (per result)
  lang             string[] ISO 639-1, preference not a filter
  published_after  date   YYYY-MM-DD
  published_before date   YYYY-MM-DD
  domains          { include: string[], exclude: string[] }  <= 50 each
  highlights       int    0-5, default 0
  timeout_ms       int    500-30000, default 15000
  links            enum   none | relevant | all, default relevant
  context          { enabled, strategy: summary|evidence, max_tokens, citations, dates }

RESPONSE 200
  id        string
  query     { text, language }
  results[] { url, title, site, published|null, retrieved, language,
              score, text|null, highlights[{text,start,end}] }
  context   optional { strategy, input_tokens, output_tokens, sources[] }
  links[]   discovered links; relevance-filtered by default
  coverage[] extraction coverage for returned source versions
  usage     { searches, results, context_input_tokens,
              context_output_tokens, cost_usd }
  took_ms   int

ERRORS  { error: { type, message, retryable, retry_after?, request_id, docs } }
  retryable types: rate_limited (429), internal (500), capacity (503), timeout (504)
  terminal types:  invalid_request (400), invalid_key (401), quota_exhausted (402),
                   query_too_long (413), unsupported_filter (422)
  Branch on error.type, never on error.message.
  Retry with exponential backoff AND jitter. Honour retry_after when present.

RULES THAT MATTER
  1. Write query as a question, not keywords. Semantic ranking rewards it.
  2. Do not put a year in the query to get recent pages; use published_after.
  3. Returning fewer rows does not change the selected mode price; max_chars changes downstream token cost.
  4. In a loop: content:"none" first, then re-query the two or three survivors
     with content:"text". Saves ~40ms and most of the context.
  5. published may be null. Never fabricate a date; say the source is undated.
  6. score is comparable within one response only. Do not threshold on it.
  7. Cite from highlights[].start/end, not from the model's memory of the text.
  8. A 504 is not billed. Degrading beats retrying twice for most agents.

PRICE  New Search: Fast $2.99 · Standard $4.99 · Pro $7.99 · Deep $9.99 · Ultra $13.99
       Search + Compact: $4.99 · $6.99 · $11.99 · $14.99 · $19.99
       per 1000 searches. usage.cost_usd is returned on every response.

Machine-readable sources

MCP server

Orbita speaks the Model Context Protocol, so Claude Code, Cursor and anything else that speaks MCP can call it without you writing a wrapper.

{
  "mcpServers": {
    "orbita": {
      "command": "npx",
      "args": ["-y", "@orbita/mcp"],
      "env": { "ORBITA_API_KEY": "orb_live_..." }
    }
  }
}

It exposes one tool, orbita_search, with the parameters above, including Auto, Context and links. One tool on purpose: the model picks capabilities through parameters instead of choosing among near-duplicate tools.

Claude Code can use the documented mcp.json entry; Cursor can register the same command under MCP settings; a custom MCP client should expose the same orbita_search input schema and pass the API key server-side. The local prototype includes a stdio reference server at prototype/src/mcp-server.mjs; its only search tool calls the local v1.1 API. The browser UI may also expose a separate read-only status capability, not a second search contract.

Migration map

Field by field, from whatever you are on now. Where a concept does not exist on the other side we say so instead of inventing an equivalent.

OrbitaExaTavilyLinkupBraveSerper
queryqueryqueryqqq
limitnumResultsmax_resultsmaxResultscountnum
content: "text"contents.textinclude_raw_contentincludeSources— snippets only— snippets only
max_charscontents.text.maxCharacters
modetypesearch_depthdepth
published_afterstartPublishedDatetime_rangefromDatefreshnesstbs
domains.includeincludeDomainsinclude_domainsincludeDomainsvia site:
langcountrysearch_langhl / gl
highlightscontents.highlightsextra_snippets
results[].publishedpublishedDate— not returned— not returnedpage_agedate
usage.cost_usdcostDollarscredits
mode: "auto"
context.strategy: "evidence"contents.textinclude_raw_contentincludeSources
linkslinks
Two things that bite during a migration. Provider modes are not equivalent: the 2026-09-09 run used Exa Fast, Tavily Basic and Linkup Standard. Date fields also need a null-safe path. Their measured presence among returned results was 64.0% for Exa, 39.5% for Orbita, and 0% for the Tavily and Linkup modes called in this run; that is a measurement of these responses, not a claim that a provider can never return a date.

How we compare

Corrected Search100 replay

The original 100-query responses remain unchanged. The current Fast-to-Standard consistency rule is replayed over them and the original score formula is applied without manual adjustment.

Orbita modeQualityHit@1Hit@5Hit@10MRRnDCG@10
Standard80.0165%88%91%0.73630.7789
Fast79.3765%88%88%0.73170.7686
Replay, not a new live run. No provider was called again. Latency was not replayed and remains historical until the next frozen benchmark.

Original Search100 — measured 2026-09-12

The original values remain available for auditability and are not silently rewritten after the consistency correction.

Provider / modeQualityHit@1Hit@5Hit@10Hit@10 95% CIMRRp50p95
Orbita Fast79.3765%88%88%80.19–93.00%0.7317836 ms*5 672 ms*
Orbita Standard76.0661%81%88%80.19–93.00%0.69905 394 ms*16 746 ms*
Exa Fast68.2362%67%67%57.31–75.44%0.6400624 ms970 ms
Linkup Standard52.9238%52%61%51.20–69.98%0.44981 327 ms2 312 ms
Tavily Basic35.9718%37%40%30.94–49.80%0.25742 065 ms4 402 ms

Quality = Hit@1 25% + Hit@5 20% + Hit@10 15% + MRR 20% + nDCG@10 10% + delivery 10%. All 500 calls returned successfully. *External and Orbita timings have different measurement boundaries and are not directly comparable. One AP-title Standard outlier took about four minutes and remains in the frozen record.

Consistency correction applied. The run exposed a case where the broader mode could move a strong Fast result downward. Fixed modes now preserve strong Fast results while adding depth. The replay above shows the corrected rank outcome; a new live run is still required for fresh latency and repeatability evidence.

All known target pages were confirmed before the frozen run. Corpus size and internal index statistics are not public. Equivalent published-rate external spend: $2.00.

Historical benchmark — measured 2026-09-09

This preserved prototype run used 20 pre-registered questions, one known publisher URL per question, top ten from each provider, and no LLM judge. A hit means that exact URL appeared at or above the stated rank after URL normalisation.

ProviderHit@1Hit@3Hit@5Hit@10MRRp50p95Date field
Orbita prototype100%100%100%100%1.0004 556 ms4 938 ms39.5%
Exa fast40%50%50%50%0.433245 ms645 ms64.0%
Tavily basic10%15%25%25%0.1501 030 ms2 313 ms0%
Linkup standard10%30%30%50%0.2031 809 ms2 886 ms0%

Quality used one request per question/provider. Latency used six fixed sentinel queries × two clean passes, giving 12 samples per provider; all four providers had zero request errors. Orbita's p50 and p95 are prototype end-to-end measurements, not a production SLA.

Read the result narrowly. Orbita searched a deliberately prepared frozen corpus containing all known target pages; its size and internal index statistics are not public. The competitors searched their own web indexes. This tests where known pages rank after intake; it does not prove broader web coverage, answer correctness, or superiority on Ukrainian law, shopping, news, or the whole web. Twenty quality samples and 12 latency samples per provider are a prototype check, not an SLA.

Result diversity

Average number of unique domains in each top ten from the same 20-query quality run.

ProviderAverage resultsAverage unique domains
Orbita10.04.3
Exa10.07.5
Tavily9.18.3
Linkup10.08.6

Unique-domain count is a diversity indicator, not a quality score. Orbita's 4.3 shows that the deliberately narrow frozen corpus repeated publishers more often than the three web-scale providers.

Vendor-published information

The figures below come from provider documentation or marketing; they are not results from the Orbita benchmark above.

ProviderPublic price used / quotedVendor-published latency or service claim
Exa$7 / 1k Fast searches, up to 10 resultsFast <350 ms end-to-end p50 in Exa's 2.0 test; configurable 180 ms–1 s
Tavily$5–8 / 1k Basic/Fast at published credit pricesNo numeric public latency SLA; the API reports response_time per request
Linkup$5 / 1k Standard raw resultsStandard 1–3 s; homepage claims SLA-backed 99.9% uptime
Serper$0.30–1.00 / 1k by prepaid volumeUsually 1–2 s, sometimes 2–4 s; not measured here because no current project key was present

Sources: Exa pricing, Exa 2.0, Tavily credits, Tavily Search API, Linkup pricing, Linkup modes, and Serper.

Hard test budget: $1.00. Estimated spend at published rates: $0.640 for completed web-provider calls, plus a conservative $0.01 Orbita reserve. The web-provider amount is an estimate, not an invoice export.

See the interactive chart on the landing page

Changelog

2026-09-13
Search100, pricing and resilient intake. Published 500 first-attempt provider/mode results with confidence intervals and strata; improved corpus intake, query-body redaction, staging account/API verification and customer-facing .99 pricing. Corpus size remains private.
2026-09-12
Orbita Gravity named and documented. Published customer-visible behavior, measured outcomes and a public-capability comparison while keeping implementation details proprietary.
2026-09-09
Head-to-head benchmark replaced. Published the pre-registered exact-URL test across Orbita, Exa, Tavily and Linkup, including rank metrics, latency, date-field presence, result diversity, modes, spend and the closed-corpus limitation. Vendor-published claims are now shown separately.
2026-08-07
Accounts and keys are self-serve. Sign up with a login, an email and a password; keys are created, revealed once and revoked from the dashboard, which also carries usage, per-key spend, latency percentiles and a playground. Keys are no longer issued by hand.
2026-08-06
Documentation published. This site, plus llms.txt, llms-full.txt and an OpenAPI description.
2026-07-22
Result ceiling set at 50. Above that the marginal source stopped changing answers and only cost context.