Nyne.ai Documentation Audit
The agent-facing scaffolding (llms.txt, manifest, per-endpoint .md mirrors, MCP quickstart) is unusually thorough for a B2B data API — but the four "sources of truth" for the API surface disagree with each other, key labeled links 404, the Usage page is rendering raw Perl HASH(...) references where credit costs should be, the hosted MCP advertises twice the tools it documents, and the two open-web Discovery endpoints are near-duplicates with confusingly similar siblings (discover, discovery, search, leads).
1. Usage / Credit Counting page is rendering raw Perl HASH() references instead of credit costs (critical)
Location: https://api.nyne.ai/documentation/usage
Problem: The page that explicitly exists to explain credit math has serialized Perl scalar refs leaking into the rendered HTML. Quoted verbatim:
"Search results: HASH(0x55aa05541558) × 3 = 282566166593544 credits (HASH(0x55aa05541558) per result returned)" "Total credits: 565132336453584 credits" "Person Search API: HASH(0x55aa05541558) credits per search result returned" "Person Enrichment API: HASH(0x55aa0564b298) credits per enrichment performed"
Every per-unit credit value on the Credit Breakdown list is a HASH(0x...) ref, and the "Example: Search with Enrichment" arithmetic prints astronomically wrong totals (565 trillion credits for a 3-result search).
Consequence: The single page meant to be authoritative on credit cost is unreadable. A developer trying to estimate cost before integrating gets gibberish; the only way to recover credit costs is to read each endpoint's separate "Credit Usage" section (e.g. Person Search lists 1/5/14/2 etc.) and reconcile by hand. Agents that scrape this page will ingest the broken numbers as if they were real.
The fix: Fix the template — the rendering code is interpolating a Perl hashref (likely a config blob) instead of dereferencing the integer cost. Replace with the per-endpoint costs that already exist elsewhere (Person Search = 1, Person Enrichment = 6, etc.) and add a regression test that asserts the rendered page contains no HASH(0x substring.
2. Four "sources of truth" for the API surface disagree on which endpoints exist (critical)
Location: /documentation (landing + sidebar + footer), /llms.txt, /.well-known/nyne-api.json, /documentation/person, /documentation/company
Problem: The same product is enumerated four different ways and none of them agree:
- Landing page header tiles: "All APIs (26) — Person (15) — Company (10) — Other (1)"
- Sidebar: 18 Person entries (incl. Lookup Fields, Single Social Lookup, Social Account Validator, Social Interactions, Personal Interests, Person Leads, Person Ask, Person Discover, Simulation, Competitor Engagements) and 11 Company entries
- Section page headers: "Person APIs — 17 APIS — 17 PLAYGROUNDS" and "Company APIs — 11 APIS — 11 PLAYGROUNDS"
llms.txt: 16 Person + 8 Company + 1 Other = 25- Manifest (
nyne-api.json) endpoints array: only 10 person endpoints listed - Footer: 8 Person + 9 Company labels, omits Lookup Fields, Single Social Lookup, Social Account Validator, Social Interactions, Personal Interests, Person Leads, Person Ask, Person Discover, Simulation, Competitor Engagements
Concretely: Lookup Fields API has a full doc page at /documentation/person/lookup-fields and a playground, but is missing from both llms.txt and the manifest's endpoints array. Social Account Validator, Social Interactions, Personal Interests, Simulation are in the sidebar but absent from llms.txt.
Naming also drifts even where coverage doesn't: the sidebar names "Social Newsfeed API," "Personal Interests API," and "Social Interactions API," while llms.txt names the same endpoints "Person Newsfeed API," "Person Interests API," and "Person Interactions API." An agent grepping for a known label across the two indexes can miss the match entirely. The sidebar and footer also list a bare "Discovery API" under both Person and Company sections — same label, different endpoints, no disambiguator in the nav.
Consequence: Nyne's own docs tell agents to "Read llms.txt for the index, use the manifest to choose the right endpoint." An agent that follows that instruction will never discover Lookup Fields, Simulation, Social Account Validator, etc. Human developers comparing the section header ("17 APIs") to the sidebar (18 entries) to the landing card (15) have no way to know which is canonical, and there is no changelog to disambiguate.
The fix: Generate llms.txt, the manifest's endpoints array, the sidebar, the footer, and the section-header counters from a single source. Standardize endpoint display names across all indexes (pick "Person Newsfeed" or "Social Newsfeed" — not both). Disambiguate the two "Discovery API" nav entries (e.g. "Person Discovery" / "Company Discovery"). Then publish a one-line "last generated" stamp so contradictions surface in CI rather than in customer integrations.
3. Labeled "Agent Manifest" and "MCP Quickstart" links resolve to slugs that 404 (critical)
Location: /documentation (landing + footer), /documentation/agent-manifest, /documentation/mcp-quickstart
Problem: The "For AI Agents" section on the documentation root prominently lists "Agent Manifest" and "MCP Quickstart" as machine-readable entry points. The footer's Resources list repeats them. But:
/documentation/agent-manifest→ HTTP 404 ("Page Not Found"). The real manifest lives at/.well-known/nyne-api.json./documentation/mcp-quickstart→ HTTP 404. The real quickstart lives at/documentation/mcp/quickstart(note the slash, not hyphen).
Consequence: Both of these are advertised as the agent-onboarding entry points — the audience least equipped to "click around and guess." An agent that lands on the docs root and follows the labeled link gets a 404 page, no manifest, and no MCP guidance. Same for a human who right-clicks the footer link. This entirely defeats the purpose of having a curated agent-facing index.
The fix: Either (a) add 301 redirects from /documentation/agent-manifest → /.well-known/nyne-api.json and /documentation/mcp-quickstart → /documentation/mcp/quickstart, or (b) replace the labeled links on the docs root and footer with the actual URLs. A sitemap/link-check should be wired into CI to prevent the next dead-label regression.
4. Hosted MCP advertises 6 tools; the Quickstart only documents 3 (significant)
Location: /.well-known/nyne-api.json (manifest mcp.hosted.supported_tools), /documentation/mcp/quickstart ("Credits & Pricing" table), /mcp (live MCP manifest)
Problem: The agent manifest declares the hosted MCP's supported tools as:
"supported_tools": ["search","fetch","search_people_semantic","get_person_profile","ask_profile","check_status"]
The Quickstart's "Credits & Pricing" table documents costs and behavior for only three of them — search_people_semantic (4 credits), get_person_profile (6 credits), and ask_profile (6 credits). search, fetch, and check_status are nowhere in the Quickstart's cost table or its tool descriptions, and the live /mcp manifest confirms search is a real tool with its own contract ("Returns {request_id:'abc123'}").
Consequence: An MCP client wired against /.well-known/nyne-api.json's tool list will call search, fetch, or check_status and have no documented credit cost, no documented schema, and no way to validate request shapes before billing hits. The Quickstart's "MCP uses the same credit costs as the REST API" claim only holds for the three tools it actually covers.
The fix: Either (a) extend the Quickstart pricing table and tool reference to cover all six tools the manifest advertises, or (b) trim supported_tools to only the documented three and move search/fetch/check_status to a clearly marked "Preview / undocumented" section. Source the list of supported tools from the same place the server registers them so the two can't drift.
5. MCP protocol version on Quickstart contradicts the live MCP manifest (significant)
Location: /documentation/mcp/quickstart vs. /mcp
Problem: The Quickstart's "Quick Reference" table says:
"Protocol Version | 2024-11-01"
The live MCP manifest served at /mcp (the same URL the Quickstart tells users to register in ~/.claude/mcp.json) responds with:
"protocolVersion":"2025-06-18"
Consequence: MCP clients negotiate based on protocolVersion. Developers wiring up Claude Desktop or another MCP client against the documented 2024-11-01 will either ignore newer fields the server now emits, or attempt a downgrade and get unexpected behavior. Agents that read the docs to decide which spec to validate against will validate against the wrong one.
The fix: Update the Quickstart table to 2025-06-18 (or whatever the server is actually advertising), and source the value from the same config the server uses so it can't drift again.
6. Callback URL scheme requirement contradicts itself across Company endpoints (significant)
Location: /documentation/company/search, /documentation/company/enrichment, /documentation/company/employees
Problem: Three sibling Company endpoints disagree on whether plain HTTP callbacks are allowed:
- Company Search:
callback_urlfield is "HTTPS endpoint that receives the completed payload"; errorinvalid_callback_url – Callback URL is not HTTPS. - Company Enrichment: error
invalid_callback_url – Callback URL is not HTTPS. - Company Employees:
callback_urlis "HTTP or HTTPS endpoint that receives the completed payload automatically"; errorinvalid_callback_url – callback_url is not a valid HTTP or HTTPS URL.
Consequence: A developer wiring a single callback receiver for all three endpoints can't tell whether plain http:// is supported. If the server actually rejects HTTP everywhere, Employees docs lie and customers will register a non-functional endpoint; if the server allows HTTP on Employees only, that's a quietly insecure default that contradicts the rest of the surface (and that a security review will flag).
The fix: Decide whether the platform requires HTTPS callbacks or accepts HTTP. Make the rule uniform across endpoints (recommend HTTPS-only), and update the field description and invalid_callback_url error text identically on all three pages.
7. Four near-identical endpoint names — search, discover, discovery, leads — with overlapping behavior (significant)
Location: /documentation/person/search, /documentation/person/discover, /documentation/person/discovery, /documentation/person/leads (and the symmetric Company pair /company/search vs. /company/discovery)
Problem: Nyne ships four people-finding endpoints whose slugs are minor variants of each other. The manifest itself flags the risk in its notes:
"Use routing guidance instead of inferring endpoint choice from similar names like search, discover, discovery, and leads."
But the disambiguation only exists as a prose table on the Person APIs section page; there is no naming convention that surfaces in the slug, and the Person Discovery and Company Discovery pages are near-textual duplicates ("Discover people from the open web..." → "Discover companies from the open web..." with the same status enum pending/searching/completed/failed, same basic/standard/premium tiers, same 10-credit cost). Meanwhile each endpoint has its own status enum (Person Search = sync-shaped 200, Deep Research = pending/enriching/gathering/analyzing/completed/failed, Person Ask = pending/processing/completed/failed, Person Discovery = pending/searching/completed/failed), so picking the "wrong" near-duplicate also means rewriting the polling loop.
Consequence: Agents (and humans) routinely pick the wrong endpoint based on slug, then have to rewrite their integration when they discover a different one fits better. The manifest's own routing-guidance note is an admission that customers were getting confused.
The fix: (1) Rename or alias the slugs to encode their job — e.g. /person/icp-search, /person/keyword-discover, /person/openweb-discovery, /person/social-leads. (2) Pull the routing table out of the section page and put a one-line "Use this instead if..." pointer at the top of each overlapping endpoint's page. (3) Standardize the status enum across all async endpoints so polling code is portable.
8. Manifest's status_model.in_progress lists 14 states; no single endpoint emits more than a handful (significant)
Location: /.well-known/nyne-api.json (status_model.in_progress) vs. /documentation/person/ask, /documentation/person/deep-research, /documentation/person/discovery, /documentation/company/discovery
Problem: The manifest declares a unified in_progress enum of 14 states:
["pending","queued","processing","finding","fetching","analyzing","enriching","gathering","aggregating","searching","discovering","running","started","in_progress"]
But each documented async endpoint emits a small, endpoint-specific subset:
- Person Ask:
pending,processing(2) - Deep Research:
pending,enriching,gathering,analyzing(4) - Person Discovery / Company Discovery:
pending,searching(2)
States like finding, aggregating, discovering, running, started, in_progress appear on no documented endpoint.
Consequence: An agent or SDK author writing a single polling client against the manifest's unified status enum will allocate handlers (and possibly UI states) for statuses that no endpoint will ever return — and, more worryingly, has no way to know which subset applies to which endpoint without reading every page. Per-endpoint status enums are documented prose, not declared anywhere parseable.
The fix: Either (a) shrink status_model.in_progress to the union of states actually emitted, or (b) per-endpoint, declare an in_progress subset on each endpoints[*] entry in the manifest. Then standardize names where they overlap (e.g. searching on Discovery, analyzing on Deep Research) so client code can branch on a known closed set.
9. The "Other (1)" endpoint — Usage — is HTML-only and absent from the agent manifest (significant)
Location: /llms.txt, /documentation/usage, /.well-known/nyne-api.json
Problem: llms.txt lists a single "Other" entry:
Usage API: Check API usage, credits, and rate limit status (HTML only).
The Usage API is the endpoint an agent needs to monitor credit burn before submitting an expensive Deep Research (100 credits) or large Company Employees (up to 4,500 credits) job. It is explicitly flagged "HTML only" — no .md mirror, no manifest entry, no JSON schema.
Consequence: Agents following Nyne's recommended workflow ("Read llms.txt → manifest → endpoint .md") cannot programmatically inspect the Usage endpoint's request/response shape, even though Usage is the precondition for cost-safe usage of every other endpoint. Combined with finding #1 (the Usage page is currently broken anyway), the credit-accounting surface is opaque to automation end-to-end.
The fix: Publish /documentation/usage.md with parameters, response schema, and rate limits, and add a corresponding entry to the manifest's endpoints array. Once the page itself (finding #1) is repaired, the markdown mirror should regenerate from the same source.
10. Person Search response is documented as sync but the request body accepts async pagination tokens (minor)
Location: /documentation/person/search
Problem: The page documents a single response code:
"200 Search completed successfully"
…but the documented request body accepts cursor and request_id parameters, qualified with "Required unless cursor or request_id is provided for pagination." Sibling async endpoints (Deep Research, Person Ask, Discovery, Company Employees) all document a request_id + polling contract instead of a 200.
Consequence: Either the endpoint is actually async with pagination tokens and the documented "200 Search completed successfully" hides a polling contract callers need to implement, or the cursor / request_id fields are dead parameters. Either way, a developer writing a Person Search client based on the documented surface can't know whether to expect immediate results or a request_id to poll, and can't tell which pagination shape cursor actually accepts.
The fix: Pick one. If Person Search is async, document the request_id polling contract and status enum the way Deep Research does. If it is sync, remove cursor/request_id from the request body documentation or move them to a clearly labeled "Pagination of previously returned results" section with an explicit pagination response shape.
11. Support email contradicts itself between pages (minor)
Location: /documentation (root) vs. /documentation/mcp/quickstart
Problem: The documentation root's Getting Started footer says:
"Support: support@nyne.ai"
The MCP Quickstart's "Need Help?" section says:
"Email Support: support@nyne.com"
Two different TLDs for the same support address on the same docs site.
Consequence: A one-character typo, but nyne.com is not the platform's apex domain. If Nyne doesn't own nyne.com, MCP-integration support requests are leaking to a third party (potentially with API key context attached). If Nyne does own it but doesn't route mail, the messages bounce silently — and the developers hitting MCP issues (the agent-novel surface) are the ones being routed wrong.
The fix: Pick one canonical support address (almost certainly support@nyne.ai), grep the docs for the other variant, fix, and verify ownership/routing of nyne.com either way.
12. Sitemap lastmod is fixed across 83 entries and predates manifest version by 12 days (minor)
Location: /sitemap.xml vs. /.well-known/nyne-api.json
Problem: The sitemap lists all 83 URLs with an identical lastmod of 2026-04-28 and a monthly changefreq. The agent manifest at /.well-known/nyne-api.json reports "version": "2026-04-16". Today is 2026-05-15, so the sitemap claims everything was updated 17 days ago, the manifest claims a generation date 29 days ago, and there is no other timestamp on any doc page.
Consequence: Crawlers and agents cannot tell which pages have actually changed, and the sitemap's blanket date is effectively useless for incremental indexing — every doc has to be re-fetched on every cycle. Combined with the cross-doc contradictions above, there is no way for a downstream consumer to know whether llms.txt or the manifest is the "newer" view.
The fix: Emit a real per-URL lastmod from your build system, surface a version/last-updated stamp on each doc page, and bump the manifest version whenever the endpoints array changes.
13. /documentation.md returns 404 despite the instruction to "append .md to any endpoint documentation path" (minor)
Location: /documentation.md, /documentation ("For AI Agents" panel)
Problem: The agent-facing intro says:
"switch to page-specific markdown by appending .md to any endpoint documentation path."
But /documentation.md itself returns HTTP 404. Per-endpoint markdown mirrors (e.g. /documentation/person/enrichment.md) do work; the rule simply doesn't apply to the documentation root.
Consequence: Agents that follow the instruction literally and start at the root get a 404. Minor because workarounds exist (use llms.txt for the index), but it contradicts the explicit instruction the same page gives.
The fix: Either generate /documentation.md as a markdown index (a copy of llms.txt with section descriptions would suffice), or qualify the instruction to "append .md to any endpoint documentation path" and remove the implication that the root is markdown-accessible.
14. llms-full.txt is not served (minor)
Location: /llms-full.txt
Problem: The conventional companion to llms.txt — a single concatenated full-text bundle — returns HTTP 404. Many comparable AI-doc setups (Mintlify, Docusaurus AI plugin) expose it.
Consequence: Agents that want to load the entire docs corpus in one fetch must follow each link in llms.txt individually. With ~25 endpoints that's ~25 round trips instead of one, and rate-limit-sensitive scraping becomes harder.
The fix: Generate llms-full.txt as a concatenation of the existing per-endpoint .md files in the order llms.txt lists them, and link it from the "For AI Agents" panel alongside llms.txt.
What they do well
- The agent-facing scaffolding exists and is unusually explicit:
llms.txt, a typed manifest at/.well-known/nyne-api.jsonwith astatus_modeland aroutingtable, per-endpoint.mdmirrors, and a hosted MCP. Most B2B data APIs at this maturity ship none of those. - The routing tables on
/documentation/personand/documentation/companyare genuinely useful — concrete "GOAL → API → WHY" rows that pre-empt the slug-collision confusion (even if the slugs themselves still need to be renamed). - Per-endpoint credit, rate-limit, and processing-stage sections are consistent in shape across the endpoints that have them (Deep Research, Discovery, Person Ask, Company Enrichment), which makes individual pages easy to read once you've landed on the right one.
Top 3 recommendations
- Fix the Usage page rendering bug (finding #1) and the dead
/documentation/agent-manifestand/documentation/mcp-quickstartslugs (finding #3) this week. These are visible-from-the-homepage breakages that any prospective customer or evaluating agent will hit in the first 60 seconds. - Make
llms.txt, the manifest'sendpointsarray, the sidebar, the footer, and the section-header counts generate from a single source. The current 4-way disagreement (finding #2) means every other improvement you make to one surface silently rots the others — and the same source should drive the MCPsupported_toolslist (finding #4) so the Quickstart can't drift behind the server. - Standardize the async polling contract across endpoints, and rename the
search/discover/discovery/leadscluster to encode their job in the slug. The manifest's own note ("don't infer endpoint choice from similar names") is a confession that slug ambiguity is hurting integrations — fix it at the URL layer, not just in prose, and shrinkstatus_model.in_progressto the states endpoints actually emit (finding #8).