Nimble Documentation Audit
Nimble's docs are broad, agent-friendly (llms.txt, llms-full.txt, per-page Markdown, downloadable OpenAPI 3.1 spec) and rich in multi-language examples — but the two pages that document the same API fundamentals (status codes, rate limits, 429 bodies) contradict each other, a published SDK example crashes with a TypeError, and the July v2 rename left "agent" meaning two different products in different corners of the site.
1. Two contradictory 429 error bodies for the same API (critical)
Location: https://docs.nimbleway.com/api-reference/introduction and https://docs.nimbleway.com/nimble-sdk/admin/rate-limits
Problem: The API Introduction documents the rate-limit error as a structured envelope: {"error": {"code": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded. Current limit: 83 QPS", "retry_after": 2}}. The Rate Limits page documents the same 429 response as a flat, differently-shaped body: {"status": "failed", "msg": "Rate limit exceeded"}. Worse, the Rate Limits page's own best practices say "Use the retry_after value to schedule next request" — a field that does not exist in the body shown three lines above it.
Consequence: Anyone writing backoff logic — human or coding agent — must parse one of these shapes. One of them is wrong, so retry code built from the wrong page silently reads undefined and falls back to blind exponential backoff, or crashes on a missing key. Agents fail silently here; they can't judge which page is authoritative.
The fix: Capture a real 429 response from sdk.nimbleway.com/v2, publish that single body on both pages (or better, in the OpenAPI spec as a 429 response schema), and delete the other version. If retry_after exists, show it in the body; if not, remove the best-practice line that references it.
2. Python SDK Map example crashes with TypeError (critical)
Location: https://docs.nimbleway.com/nimble-sdk/sdks/python (Core Methods → Map)
Problem: The example is client.map(URL="https://www.example.com", sitemap="only") with an uppercase URL keyword. The actual published package (pip install nimble_python, verified by introspection: inspect.signature(client.map) → ['url', 'country', 'domain_filter', 'limit', 'locale', 'sitemap', ...]) accepts lowercase url only. Every other Map example on the site — the Quickstart (nimble.map(url=...)) and the Map guide itself — uses lowercase.
Consequence: Copy-pasting the official SDK page's example raises TypeError: map() got an unexpected keyword argument 'URL'. This is the page a developer lands on to learn the Python client; the flagship SDK reference shipping a non-running snippet erodes trust in every other example.
The fix: Change URL= to url= on the Python SDK page, and add snippet CI that runs (or at least import-and-signature-checks) every SDK example against the released package.
3. Rate-limit header examples don't match the documented limit — or each other (significant)
Location: https://docs.nimbleway.com/api-reference/introduction (Rate Limit Headers) and https://docs.nimbleway.com/nimble-sdk/admin/rate-limits (Response headers)
Problem: Both pages state the default limit is "83 QPS (5,000 QPM)". The API Introduction's header example shows ratelimit-limit: 5000 / ratelimit-remaining: 4985; the Rate Limits page's example shows ratelimit-limit: 20 / ratelimit-remaining: 15 for the same product. Neither page says what window the header counts (per second? per minute?), and 20 matches no documented tier.
Consequence: Developers building throttling against these headers can't tell whether ratelimit-limit is a per-minute quota of 5,000, a per-second quota, or something account-specific. A monitor that alerts on "remaining < 10% of 5000" behaves absurdly if the real header value is 20.
The fix: Show one real header block, document the unit/window of ratelimit-limit explicitly, and use the same example values on both pages.
4. The two status-code references disagree on which errors the API returns (significant)
Location: https://docs.nimbleway.com/api-reference/introduction (Response Codes) vs https://docs.nimbleway.com/nimble-sdk/admin/rate-limits (HTTP status codes)
Problem: The API Introduction's table lists 200, 400, 401, 402, 422, 429, 500. The Rate Limits page's table lists 200, 400, 401, 402, 403, 429, 500, 501, 555 — no 422, but three codes (403, 501, 555 "Request Timeout") the introduction never mentions. Meanwhile the August changelog says invalid output_schema "return 422 with actionable errors", so 422 is real. The same two pages also disagree on the driver catalog: Rate Limits documents three drivers (vx6, vx8, vx10) while the Extract quickstart documents five (vx6, vx8, vx8-pro, vx10, vx10-pro).
Consequence: Error handling written from either page alone is incomplete: code built from the intro won't anticipate 403 (account blocked) or the non-standard 555 timeout; code built from Rate Limits won't handle 422 validation errors that the changelog confirms exist. Nonstandard codes like 555 especially need documenting in one authoritative place.
The fix: Maintain one canonical status-code reference (ideally in the OpenAPI spec's response definitions), make both prose pages link to it, and extend the Rate Limits driver tables to cover vx8-pro/vx10-pro or state that -pro variants share the base driver's limits.
5. "Next Steps" links on the API Introduction 404 (significant)
Location: https://docs.nimbleway.com/api-reference/introduction (Next Steps cards)
Problem: The card hrefs are missing the leading slash: href="nimble-sdk/getting-started/quickstart" and href="nimble-sdk/admin/rate-limits" (present in both the Markdown source and the rendered page's MDX payload). Resolved relative to /api-reference/, the target https://docs.nimbleway.com/api-reference/nimble-sdk/getting-started/quickstart returns HTTP 404 (verified).
Consequence: The two "where do I go next" links on the API reference's front door dead-end at a 404 for any client that resolves the relative path per URL semantics — including crawlers and agents following extracted hrefs.
The fix: Add the leading slash to both hrefs and add a link checker to docs CI that resolves relative paths the way a browser does.
6. "Agent" means two different products, and the API intro links the wrong one (significant)
Location: https://docs.nimbleway.com/api-reference/introduction (API Features), https://docs.nimbleway.com/nimble-sdk/admin/rate-limits (Agent generation)
Problem: The July changelog carefully splits the old "agents" surface into Extract Templates (/v2/extract/templates/*) and Web Search Agents (/v2/agents/*), stating "'Web Search Agents' now refers only to the new research API under /v2/agents/*". But the API Introduction still ships a feature card titled "Agent" that says "Run Web Search Agents for any website — pre-built for popular platforms, or create your own" while linking to /api-reference/extract-templates-api/run-extract-template — the Extract Templates endpoint. The Rate Limits page likewise titles the POST /v2/extract/templates/generations limit "Agent generation" and calls it "Custom agent generation... It covers both new agent creation and refinement".
Consequence: A developer (or agent) looking for the autonomous research API clicks "Agent" and lands on templates; one reading the rate-limits page concludes Web Search Agent creation is capped at 100/day when the limit actually applies to template generation. The exact confusion the v2 split was meant to end is preserved on the reference's landing page.
The fix: Rename the intro card to "Extract Templates" (and add a separate Web Search Agents card pointing at /api-reference/public-api/...), and retitle the Rate Limits section "Extract Template generation".
7. Changelog promises a "full v1 → v2 mapping" that doesn't exist (significant)
Location: https://docs.nimbleway.com/changelog/release-notes (July, breaking change note)
Problem: The breaking-change note for /v1/agents says: "See the API Reference for the full v1 → v2 mapping." The API Introduction contains no mapping — only the one-line info box that "legacy v1 endpoints keep working until they are deprecated, but new integrations should target v2." No page in the llms.txt index documents the v1 surface or a migration table.
Consequence: Users of the removed /v1/agents/run surface get a breaking-change notice whose migration reference is a dead promise. Beyond the agent → template field rename in the changelog itself, they must reverse-engineer the mapping from the v2 reference.
The fix: Publish the actual v1 → v2 endpoint/field mapping table (on the API introduction or a dedicated migration page) and link the changelog note to it.
8. Pricing page and Efforts page disagree on the top effort tier (significant)
Location: https://docs.nimbleway.com/nimble-sdk/admin/pricing (Web Search Agent) vs https://docs.nimbleway.com/nimble-sdk/web-search-agents/efforts
Problem: The Efforts page marks the max level "Custom, coming soon" and repeats "Coming soon. max removes the ceiling". The Pricing page lists "Max | Unlimited effort, you set the budget per task | 30 min-hours | Custom" as a normal, currently-orderable tier with no caveat. The pages also bill in different units ("$0.025 / task" vs "$0.025 / run") and use different level names (display label "Med" vs API value medium).
Consequence: A buyer sizing a workload off the pricing page plans around a max tier the product docs say isn't shipped yet; an agent mapping "Med" to an API value has to guess it's medium.
The fix: Add the "coming soon" flag to the Pricing table (or remove it from Efforts if max shipped), standardize on one unit word, and show the actual API enum values alongside display names.
9. OpenAPI spec leaves six operations without any security requirement (minor)
Location: https://docs.nimbleway.com/api-reference/openapi.json
Problem: The docs state "All requests require authentication using a Bearer token", and 54 of 60 operations declare BearerAuth — but six Extract Templates operations (GET /v2/extract/templates, GET/DELETE /v2/extract/templates/{name}, both versions reads, and GET /v2/extract/templates/generations/{generation_id}) carry no security field, and there is no top-level security default to inherit.
Consequence: Clients generated from the spec (a use the docs explicitly promote: "generate clients... or feed it to coding agents") will emit unauthenticated calls for these six operations and receive 401s.
The fix: Add security: [{BearerAuth: []}] at the spec root (or per-operation on the six gaps) so generated clients authenticate every call.
10. CLI template example passes invalid JSON to --params (minor)
Location: https://docs.nimbleway.com/nimble-sdk/sdks/cli and https://docs.nimbleway.com/nimble-sdk/getting-started/quickstart (Extract Template, CLI tab)
Problem: Both pages show nimble extract:templates run --template amazon_pdp --params '{asin: B08N5WRWNW}' — unquoted key and unquoted string value, which is not valid JSON. Every parallel example (Python, TypeScript, Go, cURL) passes proper JSON: {"asin": "B08N5WRWNW"}. Nothing on the CLI page says --params accepts relaxed syntax.
Consequence: If --params expects JSON (as the cURL body suggests), the flagship CLI example fails to parse; if the CLI genuinely accepts relaxed syntax, that behavior is undocumented and the example still teaches a format that breaks when moved to any other surface.
The fix: Use valid JSON in the example (--params '{"asin": "B08N5WRWNW"}') or document the relaxed syntax --params actually accepts.
11. "Contact sales" link is a mislabeled third-party chat magic link (minor)
Location: https://docs.nimbleway.com/api-reference/introduction (Exceeding Rate Limits)
Problem: "Contact sales@nimbleway.com" is labeled as an email address but links to https://login.start-chat.com/modal/...?magicLinkId=slFQ2j&UID=65ab324c-...1753267174019 — a third-party chat modal with what appears to be a user-specific magic-link token baked into public docs. The Rate Limits page routes the identical request ("need higher limits?") to a different channel entirely: "Reach out to your CS or open a via a Support Ticket" (note the "open a via a" typo).
Consequence: Developers who copy the "email address" get a chat-widget URL; if the magic-link token expires or is user-bound, the escalation path silently breaks. Two pages give two different processes for the same request.
The fix: Use a real mailto: or the Pylon portal on both pages, remove the tokenized magic link, and fix the typo.
12. Billing FAQ contradicts itself on credit rollover in one sentence (minor)
Location: https://docs.nimbleway.com/nimble-sdk/admin/pricing (Billing FAQ)
Problem: The answer to "Do unused credits roll over?" is: "Credits roll over within your billing cycle but expire at the end of each month." Data Services plans are described as "billed annually" — so does an annual-billed plan's credit expire monthly, or roll over through the cycle? The sentence asserts both.
Consequence: Customers can't determine whether unused credits from month 2 are usable in month 3 of an annual plan — a direct budgeting question the FAQ exists to answer.
The fix: State the rule concretely: the rollover window, the expiry boundary, and one worked example for an annual Data Services plan.
What they do well
- First-class agent readability:
llms.txt, a 1.7 MBllms-full.txt, per-page.mdendpoints, and a downloadable OpenAPI 3.1 spec. - Consistent five-surface code examples (Python, TypeScript, Go, CLI, cURL) on nearly every product page.
- The proxy Response Codes page is a model error reference — per-code causes, fixes, and a quick-reference table including nonstandard codes (522, 525).
Top 3 recommendations
- Create one canonical error/rate-limit reference (429 body, headers, status codes) and make the API Introduction and Rate Limits pages consume it — today they contradict each other on all three.
- Run every SDK/CLI snippet in CI against the released packages; the Python
map(URL=...)TypeError and the invalid--paramsJSON would both have been caught. - Finish the v2 rename: fix the "Agent" card and "Agent generation" heading, and publish the promised v1 → v2 migration mapping.