Orthogonal Documentation Audit
The docs are well-organized and agent-aware (llms.txt, dedicated skill file, MCP setup), but the billing/response contract is genuinely inconsistent across pages, MCP auth is unexplained, and several reference pages are one-line stubs.
1. The price/amount field has three different units across the docs (critical)
Location: /quickstart, /api-reference/run, /api-reference/details, /api-reference/list-endpoints, /mcp/tools, /api-reference/balance, /api-reference/transactions
Problem: The same conceptual field — cost of a call — is documented in incompatible units depending on which page you read:
/quickstartshows the Run response with"price": "0.10"(string, dollars) at the response root; the JS sample destructuresconst { data, price } = await response.json()and the Python readsresult['price']./api-reference/runshows the same call as"priceCents": 10(integer, cents). Nopricefield at all./api-reference/detailsshows"price": "$0.03"(string with$)./api-reference/list-endpointsshows"price": "$0.005"(string with$)./mcp/toolsshows"priceCents": 0.4— a fractional "cents" value (0.4 cents = $0.004) — which contradicts the integer-cents contract/api-reference/rundocuments for the same field./api-reference/balanceshows the same account's balance as both"balance": "$5.00"(text response) and, under/v1/credits/check,"balanceCents": 500000. 500,000 cents is $5,000.00, not $5.00 — sobalanceCentsis evidently in 1/100,000 of a dollar, not cents./api-reference/transactionsthen names that same unitamountCentsand shows-3000for"API call: apollo /v1/people/match"— but/detailslists that endpoint at$0.03. -3000 is only $0.03 if the unit is 1/100,000 of a dollar. The Python example confirms this by computingamount = tx['amountCents'] / 100000.
Consequence: An agent that follows /quickstart reads response.price, an agent that follows /api-reference/run reads response.priceCents — they break each other. An agent that uses priceCents to compute spend will be off by 1000× depending on which endpoint it called. Treasury reporting, budget caps, and "stop at $X" logic all silently produce wrong numbers. The MCP "priceCents": 0.4 is the MCP-side instance of this same root cause: a field typed as integer cents being shown as a fractional value somewhere it has to round-trip through JSON schema and TS types.
The fix: Pick one canonical unit (whole cents is the conventional choice) and one canonical field name, then sweep every example — Quickstart, Run, Details, List Endpoints, MCP Tools, Balance, Transactions. If transactions/balance legitimately need sub-cent precision, rename those fields (amountMicros, amountHundredThousandths) and document the unit explicitly in the field table.
2. Error response contract contradicts itself between the API overview and /v1/run (critical)
Location: /api-reference/introduction vs /api-reference/run
Problem: /api-reference/introduction declares the error envelope as:
{ "success": false, "error": "...", "code": "ERROR_CODE" }
and lists named codes: UNAUTHORIZED, INSUFFICIENT_CREDITS, RATE_LIMITED, NOT_FOUND, UPSTREAM_ERROR.
/api-reference/run shows a different envelope — { "success": false, "priceCents": 10, "error": "Insufficient credits..." } with no code field — and its "Error Codes" table is the HTTP numeric codes 400/401/402/404/5xx, not the named strings above.
Consequence: A developer who writes if (resp.code === "INSUFFICIENT_CREDITS") based on the overview will never match a real response from /v1/run. Agents that map code strings to retry behavior get neither contract right.
The fix: State once, at the API reference root, which envelope shape /v1/run actually returns; show a real 401/402/404 response body with the code field present; align the Run page's "Error Codes" table with the named codes (or remove the named-code list if it doesn't exist on the wire).
3. MCP setup never explains how the server authenticates the caller (critical)
Location: /mcp/setup, /mcp/overview, /mcp/tools
Problem: The setup config in every section is exactly:
{ "mcpServers": { "orthogonal": { "url": "https://mcp.orth.sh" } } }
There is no Authorization header, no headers block, no env var reference, no OAuth flow described. The Troubleshooting accordion says "Check your account has credits" — implying the server knows which account is calling — but never tells the developer how that linkage is established.
Consequence: Every MCP use call is billable. A developer following these instructions cannot tell whether their calls will be billed to them, anonymous, or rejected. Agents installed via this snippet will appear to "work" on free endpoints and then mysteriously 401 on paid ones.
The fix: Add a step that shows the actual auth mechanism — whether that's "headers": { "Authorization": "Bearer ..." } in the JSON, an interactive OAuth handshake on first connect, or an ORTHOGONAL_API_KEY env var the server reads. Whichever it is, document it in /mcp/setup and link it from Troubleshooting.
4. Apollo example transaction is inconsistent with Apollo's documented price (critical)
Location: /api-reference/transactions vs /api-reference/details
Problem: The sample transaction shows:
"type": "api_call",
"amountCents": -3000,
"description": "API call: apollo /v1/people/match"
/api-reference/details documents that exact endpoint at "price": "$0.03". If amountCents is actually in cents, -3000 represents -$30.00, which is 1000× the listed price. The numbers only reconcile if amountCents is in 1/100,000 of a dollar — which is also what the Python example below assumes (tx['amountCents'] / 100000).
Consequence: A developer comparing the catalog price to their transaction history sees a 1000× discrepancy and will assume they're being overbilled. This is the kind of thing that triggers chargebacks. This is a worked, concrete instance of Finding 1, severe enough on its own that reconciliation tooling built from these docs will silently disagree with the catalog.
The fix: Either rename the field to reflect its actual unit, or change the example to use real cent values consistent with /details (e.g., -3 for a $0.03 call) and fix the Python divisor to / 100.
5. CLI command for installing a skill is documented two different ways (significant)
Location: /index (home) vs /skill
Problem: The home page Install example uses:
orth skills add linkedin-scraper
The Agent Skill reference (/skill.md, which is the file agents are explicitly meant to read) uses:
orth skills install company-intel
Consequence: Half the agents will try add, half will try install, and one of them will fail. Humans use judgment; agents stop.
The fix: Pick one verb, replace all occurrences, and consider adding the other as an alias in the CLI itself so existing docs/snippets keep working.
6. CLI command for checking balance is documented two different ways (significant)
Location: /skill vs /api-reference/balance
Problem: /skill.md's CLI cheatsheet documents:
orth account # Check balance and usage
/api-reference/balance.md documents:
orth balance
Same operation, two verbs, in the two files most likely to be consumed by agents (the skill file and the canonical reference).
Consequence: Same shape as Finding 5 — an agent picks one verb based on which page it loaded first and stalls on command not found for the other. This is the parallel CLI inconsistency to the add/install mismatch and equally agent-breaking.
The fix: Pick one (whichever the CLI actually ships) and sweep both files. If both verbs are real, document them together with the canonical one first.
7. Authentication page is a one-sentence stub for a billable API (significant)
Location: /authentication
Problem: The entire page after the H1 is: "All requests to Orthogonal require an API key in the Authorization header:". There is no information on:
- where the key comes from (dashboard URL? account creation flow?),
- key formats —
orth_live_appears in/api-reference/introductionand/integrate, but the test-vs-live distinction (orth_test_keys, "limited APIs and no charges") only exists in/skill.mdunder "Common Gotchas", - key rotation, expiration, or revocation,
- the user-key vs organization-key distinction (mentioned only in
/api-reference/balance), - scopes/permissions.
Consequence: A developer who lands on /authentication from a search engine learns nothing they didn't already know. Critical operational facts (test vs live, org vs user) live in pages they wouldn't think to read.
The fix: Expand /authentication to cover key creation, the live vs test distinction with both prefixes, the user vs organization key distinction, rotation, and what happens when a key is leaked. Then link to it from /quickstart, /skill, and /api-reference/introduction instead of repeating snippets.
8. /api-reference/search is missing its request parameter section (significant)
Location: /api-reference/search
Problem: The scraped page for the canonical Search endpoint contains only ## Response — no ## Request block, no parameter table, no example. The MCP version (/mcp/tools#search) documents the parameters (prompt, limit) but the REST reference page that /v1/search should live on does not.
Consequence: A developer trying to call /v1/search directly (the way /quickstart shows) has to reverse-engineer the request body from the curl snippet on the Quickstart page. Agents reading /api-reference/search.md (which is in llms.txt) get an incomplete tool signature.
The fix: Add the Request section with prompt (string, required), limit (number, default 10, max 50), a curl example, and a representative response body. Mirror what's already on /mcp/tools.
9. Rate-limit documentation lists a RATE_LIMITED error but no actual limits (significant)
Location: /concepts/how-it-works, /api-reference/introduction
Problem: "How It Works" promises "We handle rate limits and retries for each provider." The introduction lists RATE_LIMITED as a returnable error code. Nowhere in the scraped docs is there a number — per-second, per-minute, per-day, per-endpoint, per-account, burst, anything — describing when Orthogonal's own gateway will return RATE_LIMITED.
Consequence: Agents and backend services can't size their concurrency, can't decide retry-with-backoff intervals, and can't tell whether a 429 is from Orthogonal or the upstream provider.
The fix: Add a "Rate Limits" section to /api-reference/introduction with the actual numerical limits (or, if limits are per-plan, link to the dashboard plan page) and the recommended backoff strategy. Distinguish between Orthogonal-gateway limits and upstream-provider limits.
10. MCP server is missing list-endpoints, the discovery tool the REST API documents (significant)
Location: /mcp/overview vs /api-reference/introduction, /skill
Problem: /mcp/overview says "The MCP server provides four tools: search, get_details, integrate, use." The REST surface and /skill.md both treat /v1/list-endpoints as a first-class discovery endpoint (it appears in the Discovery API table in /api-reference/introduction and in /skill.md's CLI cheatsheet). It is not exposed as an MCP tool.
Consequence: An MCP-only agent (which is precisely the integration model the docs push for Claude Desktop and Cursor) has no way to enumerate the API catalog — it can only search with a natural-language prompt. There's no "list everything" call, so an agent can't introspect the surface to plan multi-step workflows. This is a capability gap, not just a doc gap, but it's surfaced here because the docs don't acknowledge it.
The fix: Either add a list_endpoints MCP tool that mirrors the REST endpoint, or explicitly document on /mcp/overview that exhaustive listing is REST-only and explain the workaround for MCP-only agents.
11. "Credits" vs "dollars" is never defined, and the transactions example makes the conversion ambiguous (significant)
Location: /concepts/pricing, /api-reference/transactions, /api-reference/balance
Problem: The pricing page talks in dollars ("$0.01 as low as per call"). The transactions example shows "amountCents": 1000000, "description": "Credit purchase: 10,000 credits" — so 10,000 credits maps to 1,000,000 amountCents. If the unit is the 1/100,000-of-a-dollar interpretation forced by Findings 1 and 4, that's $10 for 10,000 credits, or $0.001/credit. None of this is stated anywhere. Balance is shown as "$5.00" (dollars) in one place and "balanceCents": 500000 (some unit) in another. There's no page that says "1 credit = $X" or "credits and dollars are interchangeable."
Consequence: A developer trying to budget — "I have $X to spend, what does that buy me?" — has to do the cross-page math themselves and reverse-engineer the unit. Compounds Finding 1: even if you trust the cents-vs-micros field, you still don't know what a "credit" is.
The fix: Add a "Credits" section to /concepts/pricing that states the credit-to-dollar conversion explicitly, document the unit on amountCents and balanceCents field tables, and make the transactions example use round numbers that obviously demonstrate the conversion.
12. Three service domains, no explanation of which is which (significant)
Location: /api-reference/introduction, /mcp/setup, /api-reference/details
Problem: The REST base URL is https://api.orthogonal.com. The MCP server is https://mcp.orth.sh. The x402 endpoints live under https://x402.orth.sh/... (visible in /details under usage.x402). Three hostnames across two TLDs are introduced as if obvious. There's no overview page that says "Orthogonal runs these endpoints on these domains, allowlist all three."
Consequence: Firewall admins and corporate networks have no clean list to allowlist. Developers confused by the orth.sh vs orthogonal.com split can't tell whether mcp.orth.sh is the real service or a phishing target.
The fix: Add a "Domains" section to /api-reference/introduction listing all three with their purposes and IP egress notes, and link to it from /mcp/setup.
13. /v1/credits/check is buried inside the Balance page without its own contract (significant)
Location: /api-reference/balance
Problem: /api-reference/balance.md is titled "Balance" and documents GET /v1/credits/balance. Halfway down, under "Check Sufficiency", it introduces an entirely different endpoint — POST /v1/credits/check — with a different request body ({"amountCents": 100}) and a different response shape (sufficient, balanceCents, requiredCents, shortfallCents). The second endpoint has no heading of its own, no parameter table, no error-response section, and isn't in llms.txt.
Consequence: Agents indexing the API surface from llms.txt will miss /v1/credits/check entirely. Developers reading the Balance page top-to-bottom will encounter a sub-endpoint without knowing its full contract.
The fix: Promote /v1/credits/check to its own reference page (with request, response, and error tables) and add it to llms.txt. Cross-link from /balance.
14. The x402 deep link points to a section that isn't visible on the pricing page (minor)
Location: /concepts/how-it-works
Problem: "See the x402 documentation for details." The scraped /concepts/pricing content only shows the "Pay Per Call" section; no #x402-direct-payment heading is present. x402 itself appears as a code-snippet format (x402-fetch, x402-python) and as a URL pattern (https://x402.orth.sh/...) in other pages, but is never explained in prose.
Consequence: Following the only narrative link to "x402 documentation" lands on a page that doesn't define x402. Developers who want to understand what they're opting into when they pay providers directly with crypto have no entry point.
The fix: Either add the #x402-direct-payment anchor and a real explanation to /concepts/pricing, or move the x402 explainer into its own /concepts/x402 page and update the link.
15. "OpenClaw" is referenced as a supported agent but never defined anywhere in the docs (minor)
Location: /index (two mentions: "Install It" step and "Why Orthogonal?" card)
Problem: The home page says "Skills work with OpenClaw, Claude Code, Codex, and any agent that reads markdown." OpenClaw is not defined, linked, or mentioned again in any scraped page — not in /mcp/overview, /mcp/setup, /skill, or the use cases. It also doesn't appear in llms.txt.
Consequence: Either OpenClaw is a real product that needs a link, or it's a typo. Either way, a reader can't verify compatibility.
The fix: If it's a real product, link to it on first mention. If it's a typo, fix both occurrences on /index.
16. The @orth/sdk TypeScript SDK has no documentation page (minor)
Location: /api-reference/integrate, llms.txt, marketing site
Problem: /api-reference/integrate shows orth-sdk snippets that import Orthogonal from "@orth/sdk", and the public landing page leads with that same SDK import. llms.txt lists no SDK reference page — no install instructions, no method signatures, no error semantics. The setup line npm install @orth/sdk && export ORTHOGONAL_API_KEY=orth_live_... appears only inside a sample response from /v1/integrate.
Consequence: A developer who picks the SDK path (which the marketing site recommends) has no canonical reference. Agents that prefer the SDK have nothing to read.
The fix: Add an SDK reference page to the docs and include it in llms.txt. At minimum: install command, client constructor, run method signature, error types.
What they do well
- llms.txt exists and is complete — every doc page has a
.mdcounterpart, which is rare and very agent-friendly. - Dedicated
/skill.mdaimed at agents with a Gotchas section that surfaces the real failure modes (key types, slug typos, MCP restart). - Use Cases page actually chains multiple APIs together rather than showing isolated snippets — this is the right shape for an agent-aware platform.
Top 3 recommendations
- Unify the money fields and define "credit". Pick one unit (cents or micros), one field name (
priceCentsoramountMicros), one credit-to-dollar conversion, and sweep every example — Quickstart, Run, Details, List Endpoints, MCP Tools, Balance, Transactions — so agents don't see three different contracts for the same number. - Document MCP authentication and parity. The setup snippet has no auth field; either show the real
headersblock or describe the OAuth handshake. While you're there, exposelist_endpointsas an MCP tool or explain its absence — MCP-only agents can't enumerate the catalog today. - Promote the test/live and user/org key facts out of the Skill file and into
/authentication, then link to it from Quickstart and the API Reference introduction. A one-sentence auth page on a billable platform is a footgun.