Skip to content
unlob

Changelog

What changed in the API and the index, most recent first.

One rate limit for the account, an honest retry-after, a 503 at capacity

  • The per-minute rate limit is now counted once for the whole account, rather than separately by each machine answering your requests. No plan figure changed — what changed is that the published figure is now the figure, in both directions, instead of a floor with undocumented headroom above it that moved with how busy we were.
  • retry-after on a rate-limit 429 is a real number of seconds instead of a constant 1: the time until your window turns over, between 1 and 60. Sleep the value you are given — a fixed one-second retry lands inside the same window and is refused again. An expensive call on a small plan is told a correspondingly longer wait.
  • A new refusal. When the service is saturated it now answers 503 immediately, with a body of "server is at capacity; retry shortly" and a retry-after, rather than holding the request in a queue until it times out. The request never ran, so it costs nothing, and it is retryable — unlike the other 503, which means no shard could serve the request and carries no retry-after. The body text and that header are how you tell them apart.
  • Unauthenticated traffic is now limited per calling address, and so are calls presenting a key that does not authenticate. The description routes — /describe, /openapi.json, /mcp/tools.json, /llms.txt, /skill.md, /guides/{slug} — stay open and cost no credits; a flood from one address is answered 429 with a retry-after. Open, not unmetered.
  • Opening an MCP session still costs no credits — initialize, the initialized notification, tools/list and ping are never billed and never touch your credits-a-minute window — but session frames now have a generous per-minute allowance of their own, so free no longer means unlimited. A client that opens a session once and reuses it will not meet it.
  • Every limit parameter is now published with a maximum of 100. A value above it is clamped rather than rejected, and the match count still reports the real total.
  • GET /metrics and GET /shards are no longer part of the public API and have been removed from the OpenAPI document. Nothing a caller needs went with them: a 503 from a search route is what tells you the data plane rather than your request is the problem.

Calls are priced in credits, by what they do

  • Plan allowances and rate limits are now counted in credits, and every call has a fixed, published cost: a search, a document fetch, similar, browse and why_not cost 1 credit; corroborate, related, authorities, dossier and path 2; assemble_context 3; ground 5; changes 10. The figures on every plan are unchanged, and a search still costs 1 credit.
  • A call that runs and fails costs 1 credit, whatever it would have cost; a refused call (401, 402 or 429) costs nothing. /account and the MCP handshake cost no credits.
  • The per-minute rate limit is counted in credits: a call takes its cost from the minute. A hard-capped key refuses a call it cannot afford in full, with a 429 and no retry-after.
  • Every response carries x-credits-charged, /describe publishes the cost table, and every OpenAPI operation carries x-credits. GET /account adds monthly_credits, credits_used_this_period and credits_remaining, and the earlier field names still answer. The ground budget reports credits_billed.

The evidence layer: ground, coverage receipts, changes

  • GET /ground and the ground MCP tool: an objective in, the smallest defensible evidence set out. Each item carries source_role, origin_type, origin, owner, independence_score, age_secs and risk_flags; the response carries a coverage receipt, a deterministic status (sufficient / insufficient / stale / partial / empty), the budget spent and next_actions.
  • Independence is computed, not host-counted: a wire dispatch and its reprints are one origin, a press release and the sites that ran it are one origin, and independent_origins counts distinct owners. independent_sources on search hits keeps its meaning (distinct hosts per story).
  • max_age is a freshness contract: evidence outside the window is reported as stale_evidence, never substituted.
  • GET /changes and the evidence_changes tool: the evidence as of an earlier instant diffed against now, plus known_urls answered like why_not. Its limitations are stated in the response.
  • Risk flags on retrieved text (instruction_like, hidden_text, role_markers, low_trust_source) on every evidence item, and risk= / strip= on /doc/{id}.
  • MCP profiles: POST /mcp?profile=grounding lists ground and get_document only; the default lists every tool. A profile narrows discovery, never permission.
  • GET /skill.md: an installable Agent Skill. /describe now reports profiles, the ground contract, the provenance vocabulary and capabilities, including on_demand_crawl: false.

Coverage graph traversal

  • Six graph endpoints are live: related, corroborate, authorities, dossier, path and assemble_context.
  • Every search hit now carries centrality, community_id, independent_sources and in_degree as stored fields, filterable and sortable at no query-time cost.
  • Corroboration counts survive deduplication — a near-duplicate rejected at admission records its host against the surviving passage.

Coverage transparency

  • why_not(url) reports present, removed with a typed reason and any replacement, or never admitted.
  • Six removal reasons are recorded in an append-only ledger: redundant, superseded, stale, access-starved, lost-replacement and tombstoned-source.

MCP server

  • Eleven tools at launch over Streamable HTTP, covering search, retrieval, coverage transparency and the six graph operations.
  • Works with Claude Code, Claude Desktop, Cursor and any other Model Context Protocol client.
  • Tool calls bill as ordinary API requests.

Plans and billing

  • Four plans: Free (1,000 requests/month), Build ($29 / 50,000), Scale ($199 / 500,000) and Archive ($799 / 2,000,000).
  • Free hard-caps at quota rather than billing unexpectedly; paid plans continue with usage-based overage.
  • Self-service key issuance, rotation and revocation in the console. Rotation is a single transaction, so there is never a window with two live keys or none.

What counts as a change

Anything a caller could observe: a new endpoint or filter, a change to what a response contains, a change to a published price or a plan limit, and material additions to coverage. Internal work that does not alter a response is not listed, because a changelog that records everything is one nobody reads for the thing that mattered.

The machine-readable surfaces move with it. The OpenAPI document, the MCP tool list and the JSON catalogues are generated from the same definitions the API serves, so a change here is a change there on the same day rather than after someone remembers to update a page by hand.

Additive by default

New filters and new response fields are added rather than substituted, so a client that ignores what it does not recognise keeps working. The practical corollary for anyone building on this is worth stating: read/describe rather than hardcoding a vocabulary, because a value set that grows is only a problem for a client carrying its own stale copy.

Where an entry changes a price or a limit, thepricing page is the current statement and this is the history. Where it changes what the index holds, thecoverage transparency endpoint will say so for any specific URL, which is a more precise answer than a line in a list.

Follow along

Notable changes are written up on the blog, which has an RSS feed.

API and MCP reference ↗