Skip to main content

Reference · Contract 2 · Public reads · No key

Company records your code can read.

Every public fact on Trooth is structured and source-labeled. Witnessed facts carry a read time and signature; an unrecorded date reads as unknown, never borrowed.

Introduction

The Trooth application programming interface (API) answers questions about software and AI companies from published records. Every endpoint in this reference is a read over an encrypted connection, in JavaScript Object Notation (JSON), with no key and no account. Public calls that change state, such as subscribing an endpoint to a company's changes, are named in the interface catalog with their side effects.

Each answer carries its own limits:

  • Where a fact came from.
  • When Trooth last read it.
  • What Trooth did not read.

No response contains a rating, grade or rank, and the schema refuses one.

What you can build

What is not offered

There is no write endpoint, test environment, software development kit (SDK) or credentialed public API; alternatives are given below.

Base URLs
AddressWhat it serves
https://trooth.coEvery endpoint in this reference
https://api.trooth.co/public/mcpThe Model Context Protocol server
https://api.trooth.co/public/trust/:slugOlder read for existing clients; Network companies answer moved, naming the supported lookup. Contract: /openapi.yaml
Client libraries
# Nothing to install.curl --version
Command line
npm install -g trooth

Two APIs, two kinds of access

Reading the Network needs no account. Writing into your own workspace needs a key bound to your client. They have different addresses, credentials and contracts; every operation below says which track it is on.

AspectPublic Network APIWorkspace API
ForAnyone reading a company's public record: buyers, tools and AI agents.A company's own workspace, sending evidence events into it.
Base addresshttps://trooth.co; the canonical read is GET /api/network/profile. The MCP server is https://api.trooth.co/public/mcp, also keyless.https://api.trooth.co
CredentialNone: no key, no account, no cookie.A workspace API key (tk_live_) bound to your client's key with DPoP (RFC 9449), sent with a new proof on every request. A key created without that binding is an ingest key that reaches only POST /v1/evidence/webhook.
ScopePublished records only; nothing private is reachable.One workspace: a key acts only for the workspace whose member created it.
LifecyclePin ?contract=2; a breaking change moves the number, with 90 days' notice under the versioning policy.A key is created by a member of the workspace, shown once and stored only as a hash; revocation takes effect on the next request.
LimitsPer client network, stated on each operation; the MCP server meters units per caller.Not published per route today; the authorization model says what each credential can reach.
Contractopenapi.json and the contract 2 schema.openapi.yaml and the authorization model.
Start hereQuickstart: one GET, no setup.API keys: create a bound key in your workspace.

Authentication

The public application programming interface (API) needs none: every endpoint reads published records.

Trooth's authenticated endpoints run the workspaces, are session scoped and are deliberately not public: a documented route map helps attackers and promises unsupported integrations. A credentialed API, if built, will be published here with scopes.

A public read
# No key, no account, no header required.curl "https://trooth.co/api/network/profile?q=example.com"
The one header you may sendoptional
Trooth-Contract: 2
Try it nowno account
npx trooth check trooth.co

Your first working call, in about five minutes

Quickstart

  1. Check the prerequisites

    Any client that speaks an encrypted connection; the samples need Node.js 18+ or Python 3.8+. No account, no key.

  2. Read a Trust Profile

    Send GET /api/network/profile with a domain in q; q=trooth.co always has an answer.

  3. Branch on found, not on the status alone

    An unknown company is 200 with { "found": false }, an answer. A 503 means Trooth could not read its own record and says nothing about the company.

  4. Read each fact with its origin

    Every entry in facts carries origin: company-declared, Trooth-witnessed or public. Show it beside the value.

  5. Pin the contract

    Send Trooth-Contract: 2 so no change of meaning arrives unannounced. The response names the contract that served it in the same header.

That works. Next, page with the cursor, follow changes, and read the production checklist.

Your first call
curl -i "https://trooth.co/api/network/profile?q=trooth.co" \  -H "Trooth-Contract: 2"

Errors

Errors are JSON with an error field; the status code carries the meaning:

  • 400: the request was malformed. The body names the field.
  • 404: the Network holds no such record. An answer, not a failure.
  • 429: a rate limit. Honor Retry-After when present; otherwise pause and retry once.
  • 502 and 503: Trooth could not read its upstream, which says nothing about the company. Retry with a bound.
  • 5xx: ours. Retry with the same bound.

Problem details, and the request id

Every API response has an X-Request-Id: send your own (20 to 200 letters, digits, + / = -) or get one. Quote it when reporting failures; a W3C traceparent you send is continued.

Send Accept: application/problem+json to /api/network/profile or /api/network/profile/history for RFC 9457 problem documents; otherwise the body is unchanged.

The document carries:

  • code, stable, and type, which links to that code below.
  • retryable, with retry_after and retry_at when a wait is known.
  • next_action.
  • errors, naming the parameter or field.
  • request_id, the same value as the header.
  • invalid_request 400 The request could not be read as sent. Next: fix_request.
  • missing_parameter 400 A required parameter is missing. Next: fix_request.
  • unsupported_contract_version 400 That contract version is not served. Next: fix_request.
  • invalid_cursor 400 That page marker cannot be used. Next: start_over.
  • cursor_expired 400 That page marker has expired. Next: start_over.
  • not_found 404 No published record answers to that identifier. Next: none.
  • version_not_found 404 That record version is not published. Next: none.
  • beyond_retention 410 That position is older than the change history keeps. Next: resync.
  • rate_limited 429 Too many requests. Next: retry_later.
  • busy 429 A request like this one is still running. Next: retry_later.
  • limiter_unavailable 503 The request limiter could not be reached. Next: retry_later.
  • capacity_saturated 503 Trooth is running as many of these as it allows at once. Next: retry_later.
  • record_unavailable 503 The record could not be read on this request. Next: retry_later.
  • history_unavailable 503 Record history is not available on this deployment. Next: use_current_record.

Retries, and where they stop

Three rules. The third is the one most often left out.

  • Retry only the classes that can change. That is 429, 502, 503 and other 5xx, never 400 or 404. On a refused cursor, restart from page one, once.
  • Count the attempts and stop. Back off, cap attempts and pages, and surface the failure.
  • An outage is not a finding. A 503 does not mean no record; keep the last good answer or show the failed read.
Status code summary
CodeMeaningRetry
200The answer. On a profile read it can be { found: false }.No
400The request was malformed. The body names the field.No
404The Network holds no such record. An answer.No
429A rate limit. Honor Retry-After when present.Yes, bounded
502No company in the request could be read.Yes, bounded
503Trooth could not read its own record. Says nothing about the company.Yes, bounded
An error body503
{  "error": "profile_read_unavailable",  "message": "The published profile record could not be read on this load. That is not the same as this company having published none, so no answer is given."}
Retry, with a bound
const RETRYABLE = new Set([429, 502, 503]);async function read(url, attempts = 4) {  for (let i = 0; i < attempts; i++) {    const res = await fetch(url);    if (res.ok) return res.json();    // 400 and 404 are answers. Sending them again gets the same answer.    if (!RETRYABLE.has(res.status) && res.status < 500) return { status: res.status, body: await res.json() };    const header = Number(res.headers.get("Retry-After"));    const wait = Number.isFinite(header) && header > 0 ? header * 1000 : 500 * 2 ** i;    await new Promise((r) => setTimeout(r, wait));  }  // An outage is not a finding: surface it, do not record "no record".  throw new Error("Trooth could not be read. Nothing is known about the company from this.");}

Rate limits

Per IP address, per minute and per hour; over either, 429 with a plain JSON message.

The record lookup allows 600 requests a minute and 20,000 an hour per client network; its history has its own budget.

Read the header before waiting. Whether Retry-After is sent depends on the route, not the status:

  • GET /api/public-mesh/{handle} sends one with its 503.
  • Some credentialed workspace routes send one with their 429.

If present, wait that long; if absent, back off and cap attempts (see Errors).

Other reads are edge-cached:

  • Directory and typeahead: a sixty second edge cache.
  • Company records: one hundred and twenty seconds.
  • A legal document: an hour.
Every public interface
InterfaceCallAccessSide effectsAvailabilitySupport
Search the directoryGET trooth.co/api/mobile/directory/searchPublic readNone: a readAvailablesupported
Featured companiesGET trooth.co/api/mobile/directory/featuredPublic readNone: a readAvailablesupported
One directory entryGET trooth.co/api/mobile/directory/vendor/{slug}Public readNone: a readAvailablesupported
A company's public rollupGET trooth.co/api/public-mesh/{handle}Public readNone: a readAvailablesupported
A company's Trust Profile (the canonical lookup)GET trooth.co/api/network/profilePublic readNone: a readAvailablesupported
A company record's published versions: the change feed, and a read of one named versionGET trooth.co/api/network/profile/historyPublic readNone: a readAvailabledocumented, not versioned
The section map: which sections each machine projection carries, leaves out, or cannot carry yetGET trooth.co/section-capabilities.jsonPublic readNone: a readAvailabledocumented, not versioned
Name suggestionsGET trooth.co/api/network/suggestPublic readNone: a readAvailablesupported
Multi-criteria discoveryGET trooth.co/api/network/searchPublic readNone: a readAvailablesupported
Batch readPOST trooth.co/api/network/batchPublic readNone: a readAvailablesupported
Network change feedGET trooth.co/api/network/changesPublic readNone: a readAvailablesupported
Network change stream (Server-Sent Events)GET trooth.co/api/network/changes/streamPublic readNone: a readAvailablesupported
Error code registryGET trooth.co/api/problemsPublic readNone: a readAvailablesupported
A legal documentGET trooth.co/api/legal/{slug}Public readNone: a readAvailablesupported
The deployed versionGET trooth.co/api/versionPublic readNone: a readAvailablesupported
A Trust Profile by workspace slug (older worker route)GET api.trooth.co/public/trust/{slug}Public readNone: a readAvailabledeprecated, with a sunset date
Public signing keysGET api.trooth.co/public/keysPublic readNone: a readAvailablesupported
A company's badge imageGET api.trooth.co/public/trust/{slug}/badge.svgPublic readNone: a readAvailablesupported
The embeddable badge scriptGET trooth.co/badge.jsPublic readNone: a readAvailablesupported
Record a profile viewPOST api.trooth.co/public/trust/{slug}/viewPublic, changes staterecords a viewAvailabledocumented, not versioned
Subscribe an endpoint to a company's changesPOST api.trooth.co/public/trust/{slug}/agent-subscribePublic, changes statestores a subscription and sends requests laterAvailablesupported
Subscribe an address to a company's changesPOST api.trooth.co/public/trust/{slug}/subscribePublic, changes statestores a subscription and sends requests laterAvailabledocumented, not versioned
Ask a company for a documentPOST api.trooth.co/public/trust/{slug}/request-accessPublic, changes statestores a requestAvailabledocumented, not versioned
MCP tool trooth_public_trust_profile: a company's complete Trust Profile, section by section, with a short summary and a link to the full recordPOST api.trooth.co/public/mcp trooth_public_trust_profilePublic readNone: a readAvailablesupported
MCP tool trooth_ai_data_use_disclosures: a company's published AI and data-use declarationsPOST api.trooth.co/public/mcp trooth_ai_data_use_disclosuresPublic readNone: a readAvailablesupported
MCP tool trooth_search_companies: search the companies published on the Trooth NetworkPOST api.trooth.co/public/mcp trooth_search_companiesPublic readNone: a readAvailablesupported
MCP tool trooth_outside_in_read: a live read of a domain's public surfacePOST api.trooth.co/public/mcp trooth_outside_in_readPublic readrequests the named site onceAvailablesupported
MCP tool trooth_verify: check the signatures on a Trust Ledger TokenPOST api.trooth.co/public/mcp trooth_verifyPublic readNone: a readAvailablesupported
MCP tool trooth_ask: a question about Trooth itselfPOST api.trooth.co/public/mcp trooth_askPublic readNone: a readAvailablesupported
MCP tool trooth_resolve_company: find a company's published record from a domain, web address, slug or namePOST api.trooth.co/public/mcp trooth_resolve_companyPublic readNone: a readAvailablesupported
MCP tool trooth_get_fact: one fact or buyer question answer from a company's recordPOST api.trooth.co/public/mcp trooth_get_factPublic readNone: a readAvailablesupported
MCP tool trooth_list_companies: list the companies published on the Trooth Network by published factsPOST api.trooth.co/public/mcp trooth_list_companiesPublic readNone: a readAvailablesupported
MCP tool trooth_company_changes: how a company's record changedPOST api.trooth.co/public/mcp trooth_company_changesPublic readNone: a readAvailablesupported
MCP tool trooth_my_company_record: your own workspace's company recordPOST api.trooth.co/public/mcp trooth_my_company_recordPrivate read, sign-inNone: a readAvailabledocumented, not versioned
MCP tool trooth_profile_get: your own workspace's Trust Profile draft and its revisionPOST api.trooth.co/public/mcp trooth_profile_getPrivate read, sign-inNone: a readAvailablesupported
MCP tool trooth_profile_checklist: what is left before your Trust Profile is published, and how to do itPOST api.trooth.co/public/mcp trooth_profile_checklistPrivate read, sign-inNone: a readAvailablesupported
MCP tool trooth_profile_update: change fields of your own Trust Profile draft, each value with its sourcePOST api.trooth.co/public/mcp trooth_profile_updateChanges the company's own profile, with its owner's agent keysaves or publishes the company's profileAvailablesupported
MCP tool trooth_profile_publish: publish your own Trust Profile draft so anyone can read itPOST api.trooth.co/public/mcp trooth_profile_publishChanges the company's own profile, with its owner's agent keysaves or publishes the company's profileAvailablesupported
MCP tool trooth_profile_domain_start: start proving your company's domain, and get its DNS TXT recordPOST api.trooth.co/public/mcp trooth_profile_domain_startChanges the company's own profile, with its owner's agent keysaves or publishes the company's profileAvailablesupported
MCP tool trooth_profile_domain_check: check your company's domain proof in DNS nowPOST api.trooth.co/public/mcp trooth_profile_domain_checkChanges the company's own profile, with its owner's agent keysaves or publishes the company's profileAvailablesupported
The A2A Agent Card: this agent's interface, not any company's recordGET api.trooth.co/.well-known/agent-card.jsonPublic readNone: a readAvailablesupported
The A2A agent: three read-only tasks over A2A 1.0, JSON-RPC bindingPOST api.trooth.co/a2a/v1 SendMessage: company_record, verify_token, askPublic readNone: a readAvailablesupported
A2A task retention: GetTask, ListTasks and CancelTask on a task only your token can read backPOST api.trooth.co/a2a/v1 GetTask, ListTasks, CancelTaskPrivate read, sign-inNone: a readAvailabledocumented, not versioned
Browser tools on every public page: search the Network, read a Trust Profile, read this pageWebMCP trooth.co trooth_search_network, trooth_read_trust_profile, trooth_read_this_pagePublic readNone: a readAvailabledocumented, not versioned
Browser tools in a signed-in workspace: read, fill, save and publish the company's own profileWebMCP trooth.co trooth_profile_read, trooth_profile_field_catalog, trooth_profile_update_fields, trooth_profile_save_draft, trooth_profile_publishBrowser publication, signed insaves or publishes the company's profileAvailabledocumented, not versioned
Read your own Trust Profile (agent)GET trooth.co/api/v1/profilePrivate read, sign-inNone: a readAvailablesupported
Change your own Trust Profile (agent)PATCH trooth.co/api/v1/profileChanges the company's own profile, with its owner's agent keysaves or publishes the company's profileAvailablesupported
Publish your own Trust Profile (agent)POST trooth.co/api/v1/profile/publishChanges the company's own profile, with its owner's agent keysaves or publishes the company's profileAvailablesupported
Agent API: prove the company's domain (POST starts it and answers the TXT record, PUT checks it)POST trooth.co/api/v1/profile/domainChanges the company's own profile, with its owner's agent keysaves or publishes the company's profileAvailablesupported
The trooth command linenpx trooth check, profile, lint, verify, log, mirror, public-record, mcp-tools, guard, declare, evidence verify, delegation verifyPublic readNone: a readAvailablesupported
Any public page as MarkdownGET trooth.co/{page}.md, or Accept: text/markdownPublic readNone: a readAvailabledocumented, not versioned
Limits
SurfaceLimitOver it
GET /api/network/profile600 a minute and 20,000 an hour per client network (an IPv4 address or an IPv6 /64), shared across instances429 with Retry-After: the seconds until that window resets
GET /api/network/profile/history120 a minute and 3,000 an hour per client network (an IPv4 address or an IPv6 /64), shared across instances429 with Retry-After: the seconds until that window resets
Every other read on trooth.coNo per-route limit. Served from an edge cache.Not applicable
GET api.trooth.co/public/trust/:slugNoneNot applicable
MCP tools/call300 units every 60 seconds per caller (OAuth subject, otherwise IP address), shared across every server instance; a tool call costs 1 to 4429 with Retry-After giving the seconds until units free up

Pagination

Use the cursor. Send limit, then each returned next_cursor as cursor until next_cursor is null. An unreadable cursor answers 400, not an empty page.

The order, and the tie-break

The cursor carries the sort key, four fields in order:

  1. Whether the company is witnessed.
  2. When it was last witnessed, most recent first.
  3. The lowercased name.
  4. The company's own identifier.

The identifier breaks ties between companies that share a name.

So every row has one position. The key is in lib/directory-rank.ts; the comparator derives from it.

What the cursor prevents

It prevents the offset failure. With offsets, companies listed mid-walk shift rows, so you silently get some twice and miss others.

A cursor names a position, so inserted rows do not shift it.

What it does not prevent

It is not a snapshot, and there is nothing to pin. Each request reads the live directory; there is no snapshot id, as-of parameter or version boundary.

Two sort-key fields move (whether and when a company was witnessed), with two unmarked outcomes:

  • An omission. A company ahead of you is witnessed mid-walk; its key moves behind your cursor and you never see it.
  • A duplicate. A company you received stops being witnessed mid-walk; its key moves ahead and you get it twice.

No cursor prevents either; a walk is best-effort discovery over a list that changes, not a consistent view of the Network.

Deduplicating, and resynchronizing

Drop repeats by slug. The omission is undetectable within one walk:

  • For a complete set, walk twice and reconcile.
  • Keep walks short, so the list moves less.
  • For a boundary, use the rows' last_scan, not your request time.

The marker always advances, so a walk cannot loop, but pages are unbounded: rows added ahead of you are served too.

Cap the pages, never resend a marker, and stop on a null next_cursor, not an empty page.

Expiry, and what the cursor is not bound to

The cursor does not expire. It holds a payload version and a position, no issue time, so old markers still work.

These get a 400 naming the reason, never a silent reset to page one:

  • A marker from an older payload version.
  • A marker that cannot be decoded.
  • A marker issued to a workspace-scoped list, used on a public one.

The cursor is not bound to your query. q and industry are not in it, so another filter returns that filter's rows after the old position, like a short page.

Keep the filter beside the cursor. total is per request and changes between pages; do not count up to it.

The cursor is opaque and belongs to this list; do not parse, build or reuse it elsewhere, where it is refused.

The offset alias, and how to migrate off it

offset and next_offset still work for clients that shipped with them. They are deprecated:

  • Responses paged by offset carry Deprecation and Link (rel="deprecation") headers pointing here.
  • No withdrawal date is set, so no Sunset header is sent; the changelog would announce one first.

Migrating takes one step. Send the offset path's next_cursor as cursor and drop offset; with both, the cursor wins.

Walk every page
# First pagecurl "https://trooth.co/api/mobile/directory/search?q=payments&limit=100"# Every next page: send next_cursor back as cursor,# and stop when next_cursor is nullcurl "https://trooth.co/api/mobile/directory/search?q=payments&limit=100&cursor=NEXT_CURSOR"

Idempotency

Every public endpoint documented here is a read, POST /api/network/batch included, so a repeat is always safe and needs no key.

Writes take one. Signed-in writes on trooth.co (publishing a profile, a domain claim, an invitation) accept an Idempotency-Key header of 8 to 255 characters, kept for 24 hours: the same key with the same request returns the stored answer, the same key with a different request is refused with 409, and the Idempotency-Status response header says which happened. Writes to api.trooth.co follow its own rule, set out under Authorization in the API documentation, where a reused key with a different request is 422.

Every public operationread only
GET  /api/legal/{slug}GET  /api/mobile/directory/featuredGET  /api/mobile/directory/searchGET  /api/mobile/directory/vendor/{slug}GET  /api/network/changesGET  /api/network/changes/streamGET  /api/network/profileGET  /api/network/searchGET  /api/network/suggestGET  /api/problemsGET  /api/public-mesh/{handle}GET  /api/versionPOST /api/network/batch

Versioning

The profile read is versioned: 2 is current; 1 and 2 are answered. Pick one with the Trooth-Contract header or contract parameter; send neither for the current one.

  • Both, disagreeing, is refused with a 400.
  • An unsupported version is refused with a 400; nothing is approximated.
  • Every answer names its contract in the Trooth-Contract header and contractVersion, and the one you asked for in requestedContract.
  • What moves the number: a removed or renamed field, or a changed meaning. Added fields do not; ignore unknown fields.

Deprecations and deadlines

Version 1 is withdrawn on 2027-03-01. It promises one answer per question, which holds only where no two sources disagree, so this version 1 response leaves out every fact two sources answered differently and names each in `withheldContested`; version 2 publishes them with every account in `conflicts`. Move to 2 and read `conflicts`. Until then, version 1 is still served, with Deprecation and dated Sunset headers.

Policy: API versioning. Each deprecation and deadline is announced first in the changelog.

Pin a contract
# In a headercurl "https://trooth.co/api/network/profile?q=trooth.co" \  -H "Trooth-Contract: 2"# Or in the querycurl "https://trooth.co/api/network/profile?q=trooth.co&contract=2"
An unsupported version400
{  "found": false,  "error": "unsupported_contract_version",  "message": "This deployment answers contract versions 1, 2 and was asked for 9. ...",  "contractVersion": 2}

Testing

There is one environment, production, and no test mode. Reads change nothing and cost nothing.

Production cannot put a company into a state on request. Two states are reliable:

  • A .invalid domain, which can never be registered, returns found: false.
  • A missing q returns 400.

For a failed read, a company with no observation and a contested fact, write fixtures from the schema; you will not meet these by chance.

Validate responses against the schema. The route is tested against it every push and deployment, so a failure is worth reporting.

Validate against the schema
# The schema the route is tested against on every pushcurl -O "https://trooth.co/schemas/network-profile.v2.schema.json"
States to cover
StateHow to reach it
found: trueq=trooth.co
found: falseq=nothing-here.invalid
400no q, or contract=9
503A fixture. It cannot be requested.
standing: nullA fixture built from the schema.
A contested factA fixture built from the schema.

The data objects

Four stable objects underpin every Trooth surface. Fields are added, never silently changed.

Company record
Identity, products and witnessed posture for one company: stable slug, domains and last-witnessed state.
Evidence receipt
One signed reading (source, scope, timestamp, signature), the base unit.
Provenance label
A closed vocabulary for where a fact came from: Trooth witnessed, Re-read on a schedule, Integration supplied, Independent third-party, Declared, Public record, Customer reported, Disputed, Stale, Unknown.
Freshness stamp
Last witnessed date, expected cadence and stale behavior, to weigh a fact by age.
# Public read. No key, no account.curl "https://trooth.co/api/network/profile?q=your-co.com"# The published record. Abridged: the response also carries contractNote,# contractOmissions, deprecation and methodology, and the full field list is# https://trooth.co/schemas/network-profile.v2.schema.json{  "found": true,  "contractVersion": 2,  "contractSchema": "https://trooth.co/schemas/network-profile.v2.schema.json",  "slug": "your-co",  "name": "Your Co",  "domain": "your-co.com",  "canonicalUrl": "https://trooth.co/network/company/your-co",  "tagline": "Payments infrastructure for marketplaces",  "industries": ["Payments"],  "updatedAt": "2026-08-22T14:03:11Z",  "witnessed": {    "standing": "witnessed",    "lastWitnessed": "2026-08-22T14:03:11Z",    "firstWitnessedAt": "2026-06-01T09:12:40Z",    "coverage": { "checksPassed": 11, "checksRun": 12 },    "continuity": {      "recordBegan": "2026-06-01T09:12:40Z",      "unbrokenSince": "2026-07-04T02:00:00Z",      "unbrokenReadings": 1176,      "totalReadings": 1904    }  },  "facts": [    {      "key": "hosting.production-regions",      "category": "Hosting",      "label": "Production regions",      "value": "us-east-1, eu-west-1",      "origin": "company-declared"    }  ],  "conflicts": []}

Reading a record correctly

Every material fact carries its source. Three rules:

  • Unknown is never no. An absent fact is no evidence either way, not a failing control.
  • Stale is not the same as wrong. A fact past its refresh window keeps its value; weigh it by the record's last reading, since facts carry no date.
  • Declared is not witnessed. Keep the two labels distinct wherever you show them.

The full vocabulary and how each state is reached is in the methodology.

One fact, in full

One entry from facts[] on GET /api/network/profile, a Trust Profile's unit:

{    "key": "hosting.production-regions",    "category": "Hosting",    "label": "Production regions",    "value": "us-east-1, eu-west-1",    "origin": "company-declared"  }

key is stable and category-scoped: Region under hosting and Region under registration are different questions.

origin is company-declared, witnessed or public-source. Blank values are not published, so unanswered reads as unanswered.

Disagreeing sources mark a fact contested, with every account under its key in top-level conflicts:

"conflicts": [    {      "key": "hosting.production-regions",      "category": "Hosting",      "label": "Production regions",      "accounts": [        { "origin": "company-declared", "value": "eu-west-1" },        { "origin": "witnessed", "value": "us-east-1, eu-west-1" }      ]    }  ]

On a contested fact, value is one account, not the answer. There is no winner field or preferred source; accounts follow a fixed origin order, not a ranking.

Five dimensions, and they are separate fields

Collapsing any two produces a wrong sentence about a real company.

  • Provenance is facts[].origin, always present: a witnessed reading or a company's answer.
  • Availability has three shapes: found: false (no record), a 503 (read failed, asserts nothing) and witnessed.standing: null (no observation on the last reading). Collapse them and an outage becomes a finding.
  • Freshness is per fact: facts[].freshness_window and facts[].stale_after, from the category windows on the methodology page, both null for a company statement Trooth does not re-read. The record contract (identity, record_summary, buyer_questions, controls_not_in_place, and per fact fact_id, anchor_url, sentence, witnessed_value and edit_history) is described in the published schema, https://trooth.co/schemas/network-profile.v2.schema.json.
  • Dispute is contested and conflicts, shown above. Uncontested means nobody answered differently, not corroborated.
  • Integrity covers one field; the response and a 200 are unsigned. If the reading behind witnessed was signed, witnessStatement holds the signed string in payload (facts, no verdict) and an Ed25519 signature, checked with the key_id key at verify/keys.

    Older readings have no statement; all other fields are unsigned.

Each response lists in contractOmissions what the contract deliberately leaves out:

  • No confidence number, per fact or overall.
  • No adjudication between disagreeing sources.
  • No completeness signal.
  • No merging of two wordings that look equivalent.

Contract version, and the alias still answered

Every response carries contractVersion (2 today). It moves only for a removed or renamed field or a changed meaning, never an added field.

Still answered: 1 and 2. Pin one; stop on unexpected values.

Version 1 is withdrawn on 2027-03-01. It promises one answer per question, which holds only where no two sources disagree, so this version 1 response leaves out every fact two sources answered differently and names each in `withheldContested`; version 2 publishes them with every account in `conflicts`. Move to 2 and read `conflicts`. Until then, each version 1 response repeats this in deprecation.

Five dimensions, five fields
DimensionRead it from
Provenancefacts[].origin
Availabilityfound, a 503, witnessed.standing
Freshnesswitnessed.lastWitnessed, methodology.freshness
Disputefacts[].contested, conflicts
IntegritywitnessStatement
Base URL
https://trooth.co
Endpoints
GET  /api/legal/{slug}GET  /api/mobile/directory/featuredGET  /api/mobile/directory/searchGET  /api/mobile/directory/vendor/{slug}GET  /api/network/changesGET  /api/network/changes/streamGET  /api/network/profileGET  /api/network/searchGET  /api/network/suggestGET  /api/problemsGET  /api/public-mesh/{handle}GET  /api/versionPOST /api/network/batch

GET /api/network/profile

Retrieve a Trust Profile

One company's canonical profile and witness facts.

Public Network API, no key · the canonical company read

The canonical published profile for a company, keyed by domain or slug, with the witness facts a buyer's tool needs: the standing field (the witnessed state), lastWitnessed (freshness), firstWitnessedAt and the unbroken run of Trooth's own hourly readings (continuity), and checksPassed out of checksRun on the signed result (coverage: checks that read as expected, out of checks run). Continuity is never claimed older than Trooth's own record and stays null until two consecutive readings agree. Responds { found: false } with 200 when no profile is published, 400 when q is missing. Cached at the edge for 120 seconds. Every response carries a methodology object stating the reading cadence, the gap tolerance that defines an unbroken series, the retention period, the per-category freshness windows, and an explicit list of coverage limits - what Trooth does not read. A caller restating witnessed or updatedAt elsewhere must carry those limits with it: neither field is a certification nor an audit opinion. Only the witness statement is signed; the profile, its facts and the company's text are not (see signing). sectionCapabilities links the section map, which says which sections this record and the other projections carry. Limited to 600 requests a minute and 20,000 an hour per client network (an IPv4 address, or an IPv6 /64), counted across server instances; over either window the answer is 429 with Retry-After set to the seconds until that window resets. If the counting store fails, each instance counts alone at the same ceilings and the read is not refused. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

qstring, in queryRequired
Company domain (example.com) or Trooth slug.
contractstring, in query
Pin the response contract version, here or in the Trooth-Contract request header (not both with different values, which is refused with 400). Omit for the current contract. A version this deployment does not answer is refused with 400 rather than approximated. Every response names the contract that served it in the Trooth-Contract response header and in contractVersion, and the one requested in requestedContract; a request for contract 1 is served contract 1 itself, with Deprecation and Sunset headers, until its withdrawal on 2027-03-01, leaving out every fact two sources answered differently and naming each in withheldContested.
sectionsstring, in query
Comma-separated categories to return facts from: identity, registration, hosting, pricing, pricing-add-ons, security, privacy, privacy-roles, recovery, ai-practices. Omit for all. An unknown name is refused with 400 and the valid list; a section's conflicts travel with its facts.
limitstring, in query
Facts per page, 1 to 200. With limit or after, a page carries up to 100 facts unless limit says otherwise; with neither, the response carries every fact in the selected sections. The response's selection object says how many facts the selected sections hold, how many this page carries and whether it was truncated.
afterstring, in query
The selection.next cursor from the previous page. It is bound to the record version and to the sections asked for: if the company publishes a new version between pages, the cursor is refused with 400 (stale_cursor) rather than served from a different record. A cursor also expires 24 hours after the page that issued it and is then refused with 400 (cursor_expired).

Returns

200
The record, or { found: false } when the Network holds none. Which body is served is keyed by the Trooth-Contract response header: 2 (the default) is NetworkProfileV2, written to the published JSON Schema https://trooth.co/schemas/network-profile.v2.schema.json and validated against it on every push and after every deployment; 1 is NetworkProfileV1, deprecated, served only to a caller that pinned contract 1, with Deprecation and Sunset headers, until its withdrawal on 2027-03-01.
400
The q parameter is missing, a contract version this deployment does not answer was requested, the query and the Trooth-Contract header asked for different contracts, a section name or limit could not be applied exactly, or an after cursor is malformed, stale or was issued for other sections.
429
Over the per-network budget. Retry-After is the number of seconds until the window that refused resets.
503
Trooth could not read its own record on this load. Retry after the Retry-After interval; nothing is asserted about the company.
Request
curl "https://trooth.co/api/network/profile?q=example.com"
Response shapefrom /openapi.json
{  "contractVersion": 2,  "contractNote": "string",  "contractOmissions": [    "string"  ],  "deprecation": "string",  "requestedContract": 0,  "contractSchema": null,  "witnessStatement": {    "payload": "string",    "signature": "ed25519:BASE64SIGNATURE==",    "key_id": "string",    "alg": "Ed25519",    "canonicalization": "string"  },  "witnessEvidenceManifest": [    {      "check_id": "string",      "source": "string"    }  ],  "signing": {    "profileSigned": false,    "signedArtifact": "witnessStatement",    "subject": "string"  },  "assuranceBoundary": {    "statement": "This record organizes source-linked information for a security review. It is not an audit, certification, or suitability decision.",    "doesNotEstablish": [      "string"    ],    "methodology": "string"  },  "found": true,  "slug": "example-co",  "name": "string",  "domain": "string",  "canonicalUrl": "https://trooth.co/network/company/example-co",  "tagline": "string",  "industries": [    "string"  ],  "updatedAt": "string",  "witnessed": {    "standing": "witnessed",    "lastWitnessed": "string",    "firstWitnessedAt": "string",    "coverage": {      "checksPassed": 0,      "checksRun": 1    },    "continuity": {      "recordBegan": "string",      "unbrokenSince": "string",      "unbrokenReadings": 0,      "totalReadings": 0    }  },  "methodology": {    "cadence": "string",    "gapTolerance": "string",    "retention": "string",    "freshness": [      {        "category": "string",        "label": "string",        "window": "string"      }    ],    "exclusions": [      "string"    ],    "summary": "string"  },  "facts": [    {      "key": "string",      "category": "string",      "label": "string",      "value": "string",      "origin": "company-declared"    }  ],  "withheldContested": [    "string"  ]}

GET /api/mobile/directory/vendor/{slug}

Retrieve a company record

One company record.

Public Network API, no key · supported

A published company profile, and its live witnessed state where Trooth has witnessed the company. A slug of the form d--example.com resolves a witnessed company that has not yet published a rich profile. Cached at the edge for 120 seconds. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

slugstring, in pathRequired
Company slug, or d--<domain>.

Returns

200
The company record.
404
The company is not on the Trooth Network.
503
The record could not be read. Not a statement about the company.
Request
curl "https://trooth.co/api/mobile/directory/vendor/example-co"
Response shapefrom /openapi.json
{  "slug": "string",  "name": "string",  "standing": "Witnessed",  "tagline": "string",  "last_scan": "string"}

GET /api/network/suggest

Suggest companies

Typeahead over published companies.

Public Network API, no key · supported

Name-to-company suggestions for a search box, over the same published listings the directory shows. Cached at the edge for 60 seconds. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

qstring, in queryRequired
Partial company name.

Returns

200
Suggestions, possibly none.
Request
curl "https://trooth.co/api/network/suggest?q=example.com"
Response shapefrom /openapi.json
{  "results": [    {      "name": "string",      "domain": "string",      "slug": "string",      "witnessed": true    }  ]}

GET /api/public-mesh/{handle}

Retrieve an evidence rollup

A company's public evidence rollup.

Public Network API, no key · supported

The buyer-facing projection of a company's evidence: the witnessed state per area (the pillars key), provider status with the time each connected system was last read. Framework rollups were retired on 2026-09-26 and the frameworks array is always empty. Individual control rows, owners and internal notes are never returned here. Each pillar carries observedAt and sourceRef, null when Trooth holds no per-area read time or reference, or when the area is restricted: null reads as unknown and is never filled from another area, a provider sync or the company's last edit. Responds 404 when the company has no public record, which is a privacy-preserving answer rather than an error. This is the read the embeddable badge performs. Cached at the edge for 300 seconds. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

handlestring, in pathRequired
Company handle.

Returns

200
The rollup, with framework percentages retired (empty) since 2026-09-26.
404
No public record for this handle.
503
The record could not be read. Not a statement about the company.
Request
curl "https://trooth.co/api/public-mesh/example-co"
Response shapefrom /openapi.json
{  "sample": true,  "company": {    "name": "string",    "handle": "string",    "updatedAt": "string"  },  "frameworks": [],  "pillars": [    {      "id": "string",      "label": "string",      "status": "string",      "observedAt": "string",      "sourceRef": "string"    }  ],  "providers": [    {      "id": "string",      "label": "string",      "status": "string"    }  ],  "rollup": [    {      "pillarId": "string",      "label": "string",      "status": "witnessed",      "counted": true,      "evidenceClass": "trooth_observation",      "observation": "string",      "sourceRef": "string",      "observedAt": "string",      "validity": {        "category": "string",        "windowDays": 0,        "validUntil": "string"      },      "freshness": "current",      "scope": {        "subject": "string",        "scope": "company",        "area": "string"      },      "unknown": [        "string"      ]    }  ],  "badge": {    "kind": "witnessed",    "line": "string",    "detail": "string",    "asOf": "string",    "counted": 0,    "witnessed": 0,    "staleAreas": [      "string"    ],    "undatedAreas": [      "string"    ],    "restrictedAreas": [      "string"    ]  },  "controls": [],  "freshness30d": 0,  "disclaimer": "string",  "retired": {}}

GET /api/version

Retrieve the serving version

The deployment currently serving.

Public Network API, no key · supported

The build stamp of the running deployment. Never cached. Useful for confirming which release answered a request. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

None.

Returns

200
The build stamp.
Request
curl "https://trooth.co/api/version"
Response shapefrom /openapi.json
{  "stamp": "string"}

POST /api/network/batch

Check many companies in one call

Check many companies in one call.

Public Network API, no key · supported

A read of up to 25 companies in one request, for an agent that plans a sequence of steps and needs to know, before acting, what each company's record says and whether it changed since planning. Each target is a domain or profile slug, or { q, pin } where pin is the record digest from an earlier read. Each result has status (listed, not_listed, withheld, unavailable), what Trooth's own readings show, the version and SHA-256 digest of the record GET /api/network/profile serves, pin.changed when a pin was sent, and plain day counts. A target that cannot be read is that target's unavailable, with the problem registry's retryable flag and next action; the other targets are still answered. It changes nothing, so it takes no Idempotency-Key and repeating it is always safe. Nothing in it grades, ranks or certifies a company. Errors are always RFC 9457 problem details. Never cached. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

None.

Returns

200
One result per target, in the order sent.
400
The body or a target cannot be used; errors[] points into the body.
413
The body is larger than 16 KiB.
429
Rate limited.
Request
curl -X POST "https://trooth.co/api/network/batch"
Response shapefrom /openapi.json
{  "format": "trooth.network-batch.v1",  "checked_at": "string",  "summary": {    "targets": 0,    "listed": 0,    "not_listed": 0,    "withheld": 0,    "unavailable": 0,    "changed_since_pin": 0  },  "results": [    {      "target": "string",      "status": "listed",      "problem": {        "code": "string",        "retryable": true,        "next_action": "retry_later",        "detail": "string"      },      "slug": "string",      "name": "string",      "domain": "string",      "record_url": "string",      "profile_url": "string",      "witnessed": {        "standing": "witnessed",        "last_witnessed_at": "string",        "first_witnessed_at": "string",        "unbroken_since": "string",        "checks_passed": 0,        "checks_run": 0      },      "record": {        "version": 1,        "digest": "string",        "recorded_at": "string"      },      "pin": {        "sent": "string",        "changed": true      },      "facts": {        "days_since_last_witnessed": 0,        "days_since_profile_updated": 0,        "unbroken_readings": 0,        "total_readings": 0      }    }  ],  "how_to_read": "string"}

GET /api/network/changes

Every record version across the Network

Every record version across the Network.

Public Network API, no key · supported

Every published record version across the Trooth Network after a position, oldest first, at most 100 per page: the company, the version, its SHA-256 digest and the previous one, and where to read it. No record body and no personal fact. Without after or since, the page starts 24 hours back. next is the cursor to send as after, and also the id of the last event, so a client can move between this feed and the event stream without losing its place. Order is by recorded time, ties broken by event id; delivery is at least once across a reconnect (drop repeats by event_id); a company that withdraws its profile stops appearing. A position older than the retention window is 410 beyond_retention. Errors are always RFC 9457 problem details. Never cached. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

afterstring, in query
next from the previous page, or an event id from the stream.
sincestring, in query
Start at this ISO 8601 date or UTC time instead of a cursor.
limitinteger, in query
Events per page, 1 to 100 (default 50).

Returns

200
A page of change events.
400
A position or limit that cannot be used.
410
The position is older than the feed keeps (beyond_retention); read the records in full and resume from a fresh position.
429
Rate limited.
503
The feed could not be read, or history is not set up on this database.
Request
curl "https://trooth.co/api/network/changes"
Response shapefrom /openapi.json
{  "format": "trooth.network-changes.v1",  "events": [    {      "id": "string",      "type": "record.version",      "event_id": "string",      "kind": "published",      "subject": {        "slug": "string",        "domain": "string"      },      "version": 1,      "recorded_at": "string",      "digest": "string",      "previous_digest": "string",      "corrects_version": 1,      "record_url": "string",      "history_url": "string"    }  ],  "next": "string",  "has_more": true,  "stream": "string",  "guarantees": {    "order": "string",    "delivery": "string",    "withdrawal": "string",    "retention_days": 0,    "body": "string"  }}

GET /api/network/changes/stream

Every record version, as Server-Sent Events

Every record version, as Server-Sent Events.

Public Network API, no key · supported

The change feed as a text/event-stream (WHATWG Server-Sent Events). Each event is event: record.version, with the same JSON an entry of GET /api/network/changes carries and id set to its cursor, so a client that reconnects with Last-Event-ID (every EventSource does) resumes exactly after the last event it received. Without Last-Event-ID or after, the stream starts now. A connection is held for about 50 seconds and closed with a comment; the client reconnects (retry: 3000). A comment is sent every 15 seconds on a quiet stream. Errors before the stream opens are RFC 9457 problem details. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

Last-Event-IDstring, in header
The id of the last event received; the stream resumes after it.
afterstring, in query
The same as Last-Event-ID, for a client that cannot set headers.

Returns

200
An event stream of record.version events.
400
A position that cannot be read.
410
The position is older than the feed keeps.
429
Rate limited.
503
The feed could not be read, or history is not set up.
Request
curl "https://trooth.co/api/network/changes/stream"

GET /api/problems

Every error code and whether retrying can help

Every error code and whether retrying can help.

Public Network API, no key · supported

The registry every RFC 9457 problem document from trooth.co draws on: each code with its status, fixed title, retryable flag, next action, and terminal (true when repeating the same request cannot change the answer, exactly not retryable). A code keeps its meaning once published. Cached for one hour. Readable cross-origin: the response carries Access-Control-Allow-Origin: * and never Access-Control-Allow-Credentials, so a browser on any site may read it without cookies.

Parameters

None.

Returns

200
The registry.
Request
curl "https://trooth.co/api/problems"
Response shapefrom /openapi.json
{  "format": "trooth.problem-catalog.v1",  "media_type": "application/problem+json",  "next_actions": [    "retry_later"  ],  "problems": [    {      "code": "string",      "type": "string",      "status": 100,      "title": "string",      "retryable": true,      "next_action": "retry_later",      "terminal": true    }  ],  "how_to_read": "string"}

For AI agents

Retrieval agents are welcome (robots.txt); model-training crawlers are blocked, since published companies did not consent to wholesale ingestion.

Cite each fact's source, and its date where it has one. When Trooth holds no record, say so.

The Model Context Protocol (MCP) server is live at https://api.trooth.co/public/mcp (JSON-RPC 2.0, public, no key). It leads with 2026-07-28, reports trooth-mcp 1.8.0 and still answers 2025-11-25, 2025-06-18, 2025-03-26 or 2024-11-05.

  • 10 tools without an account (trooth_public_trust_profile, trooth_outside_in_read, trooth_verify, trooth_ask, trooth_ai_data_use_disclosures, trooth_search_companies, trooth_resolve_company, trooth_get_fact, trooth_list_companies and trooth_company_changes), and 1 more tool that reads only the caller's own workspace with an OAuth access token. Each is read only and returns structuredContent (status, provenance, subject, summary); the table below states each one's access, what it returns, its argument limits and its cost.
  • 7 resources: trooth://buyer-questions, trooth://methodology, trooth://provenance-glossary, trooth://provenance-labels, trooth://schema, trooth://verify-a-vendor, trooth://what-a-call-sends.
  • 4 prompts: vendor_trust_check, verify_trust_token, before_you_trust, vendor_due_diligence.
All 17 tools on https://api.trooth.co/public/mcp (streamable-http transport, protocol 2026-07-28). Each call is metered against 300 units every 60 seconds per caller: the OAuth subject when a valid token is presented, a SHA-256 digest of the agent key when one is presented, otherwise the IP address. Tool policy version 2026-10-21.
ToolAccessReturnsArgumentsUnits per call
trooth_public_trust_profile
one company's complete Trust Profile on the Trooth Network, every section with its state and who said it, after a short summary that links the full record
Public, no accountPublic record data
  • company required, text up to 2,048 characters. The company's domain, such as trooth.co, or its Trooth slug; a web address is read as its host.
  • detail optional, text up to 7 characters. full, the default, returns the complete profile section by section; summary returns the short answer and is the better first call.
  • sections optional, text up to 400 characters. Comma-separated section names to return, such as security,privacy. Leave it out for every section.
1
trooth_outside_in_read
a live, neutral read of a domain's public surface right now: HTTPS reachability, five common response headers and security.txt
Public, no accountExternally fetched data, read from the named domain at call time
  • domain required, text up to 2,048 characters. The domain to read, such as example.com.
4
trooth_verify
re-check the two signatures on a Trust Ledger Token
Public, no accountA signature check of the token you send
  • token required, text up to 16,384 characters. A Trust Ledger Token, in its tlt2. or tlt. form, or its ID.
1
trooth_ask
a question about Trooth itself, answered from its fixed knowledge base
Public, no accountTrooth's own public documents
  • question required, text up to 500 characters. A question about Trooth itself.
1
trooth_ai_data_use_disclosures
what one company has declared about AI and customer data, each row labeled as the company's own declaration
Public, no accountPublic record data
  • company required, text up to 2,048 characters. The company's domain, such as trooth.co, or its Trooth slug; a web address is read as its host.
1
trooth_search_companies
search the companies published on the Trooth Network by name, domain, tagline or category
Public, no accountPublic record data
  • query required, text up to 200 characters. Words to match: a company name, a domain, or a category such as payroll.
  • industry optional, text up to 100 characters. Only companies in this industry, such as Fintech.
  • cursor optional, text up to 512 characters. The page.next_cursor of the previous answer, sent with the same query and industry.
1
trooth_resolve_company
find a company's published record from a domain, web address, Trooth slug or name, with why it matched, or every candidate when several match and none is chosen
Public, no accountPublic record data
  • identifier required, text up to 2,048 characters. A domain, web address, Trooth slug, legal or trading name, company register identifier, Crunchbase address or Wikidata ID.
  • kind optional, text up to 20 characters. What the identifier is: domain, url, slug, legal_name, registry_identifier, crunchbase_url or wikidata_id. Read from its form when left out.
1
trooth_get_fact
one answer from one company's record, by buyer question ID or fact ID, with its provenance word, date and anchor address, or which of no, not_published or not_read applies
Public, no accountPublic record data
  • company required, text up to 2,048 characters. The company's domain, such as trooth.co, or its Trooth slug; a web address is read as its host.
  • question optional, text up to 40 characters. A buyer question ID, such as q_ai_training, from trooth://buyer-questions. Give this or fact.
  • fact optional, text up to 200 characters. A fact ID, section.field, such as security.mfa_methods. Give this or question.
1
trooth_list_companies
list the companies published on the Trooth Network by industry, data region, witnessed or not, and claimed or not, in alphabetical order of record identifier
Public, no accountPublic record data
  • industry optional, text up to 100 characters. Only companies in this industry, such as Fintech.
  • data_region optional, text up to 100 characters. Only companies that publish this data residency region, such as EU.
  • cursor optional, text up to 512 characters. The page.next_cursor of the previous answer, sent with the same filters.
  • witnessed optional, true or false. true for companies Trooth witnessed, false for those it has not.
  • claimed optional, true or false. true for companies that published their own profile, false for listed domains with none.
1
trooth_company_changes
how one company's published record changed, version by version, oldest first, with each fact's edits when the record carries them
Public, no accountPublic record data
  • company required, text up to 2,048 characters. The company's domain, such as trooth.co, or its Trooth slug; a web address is read as its host.
  • since optional, text up to 40 characters. Only changes at or after this date or time, written as ISO 8601, such as 2026-10-01.
  • cursor optional, text up to 512 characters. The changes.next_cursor of the previous answer, sent with the same company and since.
  • recall_cursor optional, text up to 512 characters.
1
trooth_my_company_record
your own workspace's company record, after sign-in
OAuth access token; reads only your own workspaceCaller-private dataNone1
trooth_profile_get
your own workspace's Trust Profile draft as saved now, its revision, whether it is published and its public address
Your sign-in, or the workspace's agent key for an agent that runs on its own; reads only your own Trust Profile draftCaller-private dataNone1
trooth_profile_checklist
the steps left before your workspace's Trust Profile can be published, and how to do each
Your sign-in, or the workspace's agent key for an agent that runs on its own; reads only your own Trust Profile draftCaller-private dataNone1
trooth_profile_update
change fields of your workspace's Trust Profile draft, each value with the https source it was read from, with your sign-in; the public page changes only when the draft is published
Your sign-in, within your role, or the workspace's agent key for an agent that runs on its own; writes your own Trust ProfileCaller-private data
  • changes required, a list of up to 200 items. The changes, applied in order. Each names one field by JSON Pointer, such as /tagline, with a value and its source (the https page and the words it was read from), or state not_published with a reason.
  • if_match optional, text up to 100 characters. The revision trooth_profile_get returned. If the draft changed since, nothing is saved and the answer is revision_changed.
  • idempotency_key optional, text up to 255 characters. A key of your choosing for this exact set of changes; a retry with the same key saves nothing twice. One is made and returned when left out.
  • dry_run optional, true or false. true checks every change and saves nothing.
2
trooth_profile_publish
publish your workspace's saved Trust Profile draft so anyone can read it, with your sign-in; a first publish needs the company's domain proved, which the two domain tools do
Your sign-in, within your role, or the workspace's agent key for an agent that runs on its own; writes your own Trust ProfileCaller-private dataNone2
trooth_profile_domain_start
start proving your company's domain: the DNS TXT record to add with your DNS host's own API
Your sign-in, within your role, or the workspace's agent key for an agent that runs on its own; writes your own Trust ProfileCaller-private data
  • domain required, text up to 253 characters.
2
trooth_profile_domain_check
check the domain proof in DNS now; once it is there, the domain is proved
Your sign-in, within your role, or the workspace's agent key for an agent that runs on its own; writes your own Trust ProfileCaller-private data
  • domain required, text up to 253 characters.
2

Setup: Agents and MCP. Changes: changelog.

MCP endpointno key
https://api.trooth.co/public/mcp
Client configuration
{  "mcpServers": {    "trooth": {      "type": "http",      "url": "https://api.trooth.co/public/mcp"    }  }}

Webhooks and SDKs

Companies set webhooks in their workspace. Agents and buyers have one public route, POST https://api.trooth.co/public/trust/:slug/agent-subscribe:

  • Send a webhookUrl and get back a signing secret.
  • It follows published profiles only.
  • It sends trust.posture.changed, signed with x-trooth-signature; workspace endpoints have their own events.

Details are on Agents and MCP.

There is no full client SDK and no scoped Trooth package; any @trooth/ name is not ours. Libraries that check Trooth's signed objects exist for JavaScript (in the trooth package), Python and Go, all in the trooth-cli repository. For the API itself, use plain HTTP and JSON, or generate a typed client from /openapi.json.

One package is published to a registry: trooth on npm (source: github.com/troothllc/trooth-cli), version 0.22.1. Two of its commands:

  • trooth check <domain> reads a company's record on the Trooth Network.
  • trooth lint [path] reads what your repository declares and makes no request.

It needs no key and no account. Its other commands read a company's Trust Profile, check Trooth's signed witness statement and its public log, read what a company filed with regulators and registries, check a domain's signed declaration, decide an agent's action under your own policy, and check delegation receipts and action evidence references; npx trooth --help lists every one. trooth scan was retired and exits with an explanation.

Follow a published profile
POST https://api.trooth.co/public/trust/example.com/agent-subscribeContent-Type: application/json{ "webhookUrl": "https://your-service.example/hooks/trooth" }
The command-line client
npx trooth check example.comnpx trooth lint .

Before you go to production

Six checks, each a failure an integration has already had somewhere.

  1. Handle every class of answerA 200 with found: false, 400, 404, 429 and 5xx each need a branch. Never record a 503 as a finding.
  2. Bound retries and pagesRetry 429 and 5xx only, with backoff and a cap, then surface the failure. Cap cursor pages; never resend a cursor.
  3. Stay inside the limitsThe record lookup allows 600 requests a minute and 20,000 an hour per client network. Other reads are edge-cached.
  4. Pin the contract and watch for deprecationSend the contract header, read the deprecation field, and treat Deprecation or Sunset headers as dated tasks.
  5. Carry provenance and dates to your usersShow origin beside each value, age facts by the record's last reading, and never render unknown as no.
  6. Know what is promisedThe service level agreement and API terms state Trooth's commitments and remedies. Read both first.

The terms are the service level agreement and the API terms.

Where to watch
WhatWhere
Live availability/status
Incident history, as a feed/status/history.rss
API changes, as a feed/changelog/rss.xml?area=api
Security changes, as a feed/changelog/rss.xml?type=security
Versioning policy/api-versioning
A persondevelopers@trooth.co

Changes and status

Breaking changes are announced first in the changelog; policy: API versioning. Availability: status; GET /api/version names the answering deployment.

Questions go to developers@trooth.co.

Which deployment answered
curl "https://trooth.co/api/version"# { "stamp": "..." }

Something wrong or missing? Write to developers@trooth.co; corrections appear in the changelog.

The same record, readable by both.

Security reviewers and AI procurement agents read one record, with sources, dates and signatures.

View as agent