Every public fact on Trooth is structured, attributable, dated, and retrievable. That is what makes it useful to a security reviewer today and to an AI procurement agent tomorrow: the same record, readable by both.
Four stable objects underpin every Trooth surface. They are versioned conservatively: fields are added, never silently changed.
01
Identity, products, and witnessed posture for one company: stable slug, domains, and the last-witnessed state.
02
One signed witnessing pass: source, scope, timestamp, and signature. The unit everything else is built from.
03
A closed vocabulary for where a fact came from: witnessed, observed, integration supplied, declared, disputed, stale, unknown.
04
Last witnessed date, expected cadence, and stale behavior, so a reader (human or agent) can weigh a fact by its age.
A public read needs no key. Receipts and drift events carry the provenance and freshness the site shows, so an agent reading the API sees exactly what a person reading the page sees.
# Public read. No key, no account.curl https://api.trooth.co/public/trust/acme-ai# Response: the company record, with provenance on every fact.{ "company": { "name": "Acme AI", "domain": "acme.ai" }, "standing": "witnessed", "witnessed_at": "2026-08-22T14:03:11Z", "cadence": "hourly", "provenance": "trooth-witnessed"}{ "receipt_id": "rcpt_01J...", "subject": "acme.ai", "source": "trooth-witness-scan", "scope": "transport, dns, disclosure, supply-chain, app-sec", "observed_at": "2026-08-22T14:03:11Z", "provenance": "trooth-witnessed", "freshness": { "cadence": "hourly", "stale_after_hours": 48 }, "signature": { "alg": "ed25519", "key_id": "trooth-2026-08" }}{ "event": "posture.changed", "subject": "acme.ai", "changed_at": "2026-08-22T15:10:44Z", "from": { "standing": "witnessed" }, "to": { "standing": "attention" }, "reason": "transport check regressed", "receipt_id": "rcpt_01J..."}This list is deliberately short: if it is here, it works now. Anything not listed is not live, and Trooth does not advertise endpoints it has not shipped.
Eight operations, every one a read of published data, and none of them needs a credential. The machine-readable contract is at /openapi.json, OpenAPI 3.1, generated from the source and checked on every build.
| Endpoint | What it answers | Parameters |
|---|---|---|
GET /api/compare | Compare companies side by side | handlesrequired |
GET /api/legal/{slug} | A published legal document | slugrequired |
GET /api/mobile/directory/featured | Companies with a witnessed standing | None |
GET /api/mobile/directory/search | Search the Trooth Network | qindustrylimitcursoroffset |
GET /api/mobile/directory/vendor/{slug} | One company record | slugrequired |
GET /api/network/suggest | Typeahead over published companies | qrequired |
GET /api/public-mesh/{handle} | A company's public evidence rollup | handlerequired |
GET /api/version | The deployment currently serving | None |
The public API needs none. Every endpoint above reads records that are already published, so there is no key to request and no header to set.
Trooth does have authenticated endpoints. They are the ones this product uses to run the company and buyer workspaces, they are session scoped, and they are deliberately not offered as a public API. A documented internal route map helps an attacker and promises an integration that is not supported. When there is a credentialed API worth building on, it will be published here with scopes.
Limits are per IP address and run two windows at once, one by the minute and one by the hour. Over either, the response is 429 with a JSON body carrying a plain message. There is no retry-after header yet; a short pause and one retry is the right behaviour.
Comparison is the tightest of the reads because it fans out. Cached reads are generous: the directory and typeahead sit behind a sixty second edge cache, company records behind one hundred and twenty seconds, and a legal document behind an hour, so a well-behaved client mostly never reaches the origin.
Use the cursor. Send limit, then pass the next_cursor the response returns back as cursor. When next_cursor is null you have the last page. A cursor that cannot be read answers 400 with a sentence, rather than an empty page that looks like the end of the list.
Offset still works and is not going away, because clients already ship with it: send limit and offset and follow next_offset. It is worth knowing what you are choosing. An offset counts rows; a cursor names a position. The network grows while you are reading it, so two companies getting witnessed between your first page and your second shifts everything down: you receive two rows you already had and never see two others, and nothing about the response tells you it happened. The cursor cannot do that, because inserting a row above your position does not change which rows sort after it.
The cursor is opaque and belongs to this list. Do not parse it, build one, or carry it to another endpoint; a marker from elsewhere is refused rather than silently misread.
There is none, and every public endpoint is a read. No operation in this reference creates or changes anything, so a repeated request is safe by construction and there is no idempotency key to send.
This is worth stating rather than leaving to inference, because the answer changes the day a write endpoint appears. When one does, it will carry an idempotency key and this section will say so. Until then, any client that retries a Trooth call is retrying a read.
Errors are JSON with an error field. Status codes carry the meaning:
400 the request was malformed. The body says which field.404 the network holds no such record. This is an answer, not a failure, and it is the correct response to a company Trooth has never seen.429 a rate limit. Pause and retry once.5xx ours. Retry with backoff.Trooth records carry a provenance label and a freshness stamp on every material fact, and a client that ignores them will report things Trooth did not say. Three rules matter more than the rest.
The full vocabulary and how each state is reached is in the methodology.
Retrieval agents are welcome and robots.txt says so explicitly: an assistant answering a question about a vendor right now is the case this network exists for. Model-training crawlers are blocked, because the companies whose evidence is published here did not consent to wholesale ingestion.
Cite what you read. Every material fact has a source and a date, and an answer that carries them is worth more than one that does not. When Trooth holds no record, say so rather than filling the gap.
There is no MCP server yet. When there is, it will be announced on this page and in the changelog, with the tool catalogue and its scopes.
Webhooks are a company feature rather than a public one: a company configures them in its own workspace to push posture changes into its tools. There is no public subscription endpoint, so nothing to document here yet.
There is no SDK. The endpoints are plain HTTP and JSON, and a fetch or a curl is the whole integration. A generated client from /openapi.json works if you want types.
Breaking changes to the shape of these responses are announced in the changelog before they ship, and the versioning and deprecation policy is at API versioning. Live availability is at status, and GET /api/version tells you which deployment answered your request.
Questions go to developers@trooth.co.