Documentation
EntityRoot V1 API - Verified business facts for AI systems
Quick Start
- 1
Create an Account
Sign up at entity-root.com/register
- 2
Verify Your Domain
Add a DNS TXT record to prove domain ownership
- 3
Enter Business Facts
Add your business name, address, phone, hours, and service areas
- 4
Publish
Your facts are cryptographically signed and made available via API
Public API Endpoints
GET/ai/entity/{id}Returns cryptographically signed business facts for an entity. Bundles are Ed25519-signed and byte-for-byte mirrored to a durable S3 archive on publish.
{id} accepts either a UUID (e.g. 102a45e4-7d63-...) or a verified domain (e.g. beardemo.com.au). Both forms return the same bundle.
Example Response
{
"entity_id": "102a45e4-7d63-45b6-92f3-cfc439fe2895",
"facts": {
"@context": "https://schema.org",
"@type": "Organization",
"name": "Example Business",
"alternateName": "EX",
"url": "https://example.com.au",
"telephone": "+61 2 1234 5678",
"description": "...",
"address": {
"@type": "PostalAddress",
"streetAddress": "...",
"addressLocality": "...",
"addressRegion": "Queensland",
"postalCode": "4740",
"addressCountry": "Australia"
}
},
"hash": "ace6f0848bea876e829595f26aa785c3f8d9a8a15964756a32ce469328eeb295",
"signature": "ed25519-sig-v1:YkWfZskRdwIG0qTigWWLs2Ja3...",
"key_id": "prod-key-001",
"issued_at": "2026-05-11T04:31:21.592234Z",
"version": 6,
"schema_version": "1.0"
}GET/ai/trust-score/{id}Returns the EntityRoot V1 Identity Trust Score (0–100) computed from four equally weighted factors. Each factor is reported as a 0–100 sub-score; the top-level score is their weighted average (25% each).
{id} accepts either a UUID or a verified domain, same as /ai/entity.
Example Response
{
"entity_id": "102a45e4-7d63-45b6-92f3-cfc439fe2895",
"label": "EntityRoot V1 Identity Trust Score",
"score": 43,
"factors": {
"identity_completeness": 50,
"signing_status": 0,
"schema_compliance": 100,
"verification_depth": 25
},
"calculated_at": "2026-05-11T06:04:55Z"
}GET/ai/verify/{id}Returns verification data with masked PII for public display.
GET/.well-known/entityroot.jsonDiscovery endpoint for AI systems. Advertises the V1 public endpoints and the active signing key.
Example Response
{
"entityroot_version": "1.0",
"api_base": "https://www.entity-root.com/api/v1",
"public_key": "yqV197dIzZI0SKagXmCVZK0Akfyj6E+a/R8wydbbXNQ=",
"endpoints": {
"entity": "/ai/entity/{id}",
"trust_score": "/ai/trust-score/{id}"
},
"documentation": "https://www.entity-root.com/docs"
}GET/llms.txt?domain={domain}Machine-readable entity summary in markdown for LLM consumption.
Pass the verified domain as a query parameter (e.g. /llms.txt?domain=beardemo.com.au), or hit /ai/llms/{entityId} to fetch by UUID. When the Cloudflare worker is deployed to your origin, it forwards the bot's host header so a bare /llms.txt on the tenant domain works without a query parameter.
GET/healthHealth check endpoint for monitoring.
X-Entity-Trace Header
Every response served through the EntityRoot Cloudflare Worker includes an X-Entity-Trace diagnostic header so consumers can verify what happened on the edge.
Format:
[STATUS];[LATENCY_MS]ms;[REASON];v1Examples:
x-entity-trace: INJECTED;612ms;OK;v1 # Bot received the JSON-LD injection x-entity-trace: SKIPPED;0ms;HUMAN;v1 # Human visitor — no injection x-entity-trace: FAIL_OPEN;3349ms;TIMEOUT;v1 # Edge could not reach origin in time; original site served
| Field | Possible values |
|---|---|
| STATUS | INJECTED · SKIPPED · FAIL_OPEN |
| LATENCY_MS | Integer milliseconds from request receipt to response start |
| REASON | OK · HUMAN · TIMEOUT · ERROR |
Rate Limiting
API endpoints are bucketed into three tiers. Limits are enforced per client (IP address, or shared secret for edge callbacks) using a token bucket — sustained rate plus an instant burst.
| Tier | Scope | Sustained | Burst |
|---|---|---|---|
| public | Anonymous /ai/*, /facts/*, /.well-known/*, /llms.txt | 100 req/min | 20 |
| authenticated | JWT-bearing /api/v1/* | 300 req/min | 50 |
| edge | Cloudflare worker callbacks (/webhooks/*) keyed by shared secret | 1000 req/min | 200 |
Headers on every response:
x-ratelimit-limit: 100 # bucket size for this tier x-ratelimit-remaining: 19 # tokens left right now x-ratelimit-reset: 1778480098 # epoch seconds when bucket refills x-ratelimit-tier: public
429 Too Many Requests: retry after the seconds value in the Retry-After header (always ≥ 1).
Human Verification Page
Each published entity has a public verification page at:
https://www.entity-root.com/verify/{entityId}This page displays:
- Business name and trading name
- Masked contact info (privacy-safe)
- City/State/Country location
- Verification status and trust score
- Cryptographic signature validation
Signature Verification
Every bundle is signed with Ed25519. The signature covers the canonical (sorted-key, no-whitespace) JSON of the facts object.
Step 1. Fetch the active signing keys (JWKS-style):
GET https://www.entity-root.com/api/v1/keys/public
{
"keys": [
{
"kid": "prod-key-001",
"alg": "Ed25519",
"use": "sig",
"public_key": "caa575f7b748cd923448a6a05e609564ad0091fca3e84f9afd1f30c9d6db5cd4",
"created_at": "2026-05-11T06:15:22Z"
}
]
}Step 2. From the bundle, match the key_id field to a kid in the JWKS, parse the public key (hex), and strip the ed25519-sig-v1: prefix from the signature.
The signature payload after the prefix is standard base64.
Step 3. Re-canonicalize the bundle's facts object (RFC 8785 / JCS — sort keys lexicographically, no whitespace, UTF-8) and verify with Ed25519 against the parsed signature.
Signature format: ed25519-sig-v1:{base64-signature} · Hash format: hex(SHA-256(canonical_facts)) · same canonical bytes used for both, so verifying hash and verifying signature are equivalent checks.
Cloudflare Edge Integration
EntityRoot deploys a Cloudflare Worker to your origin that:
- Detects 30+ AI bots (GPTBot, ClaudeBot, PerplexityBot, Googlebot, etc.) via User-Agent
- Injects schema.org JSON-LD into the page
<head>for bot requests - Emits the
X-Entity-Tracediagnostic header on every response - Fails open within 3 s — never breaks your site if EntityRoot is degraded
Pre-signed bundle storage: on every publish, the backend mirrors the signed bundle to a per-domain Cloudflare KV namespace (entityroot-{domain}) under key bundle:{domain}, plus an S3 archive for durability. Operators can verify edge state via the Cloudflare KV API at any time.