Skip to content
FFN Verified Business For businesses

For AI agents and developers

Check the business is real before you book it.

The registry is built to be read by software. Look a business up by domain or phone, then verify the signed record yourself. No account, no API key.

The one rule

Trust the registry you already know, never one a page points you to. A site saying it's verified is only a claim. Pin https://registry.fofo.network in your agent's configuration and verify against it.

Verification checks the business's own signature on its profile, the registry's signature on each fact, the status lists, the delegation that lets the registry serve the record, and the DID document and DNS record on the domain. The level is recomputed from the signed facts, never read from a label.

MCP server

Streamable HTTP at https://registry.fofo.network/mcp. It offers three tools, and none of them takes a registry address, so a page can't redirect your agent to a different registry.

Tool What it does
lookup_business Finds a business by domain or phone and returns its listing (level, domains, phones), with only the registry's signature checked. Call verify_business before relying on it.
verify_business Runs the full verification for a domain: signatures, status, delegation and the two-way domain binding. Returns verified, the level, each fact and a one-line summary.
verify_presentation Checks a key-bound presentation another party gave you, for example an agent proving it acts for a business through a delegation chain. Use a nonce you generated yourself and your own origin as the audience.

Verifiers

The same checks, in your own code. Both replay the same shared test vectors.

TypeScript · @fofonet/verify-business
import { verifyBusiness, FFN_BUSINESS_REGISTRY } from '@fofonet/verify-business';

const r = await verifyBusiness('acme-hvac.com', { registry: FFN_BUSINESS_REGISTRY });
if (r.verified) console.log(r.level, r.levelName); // 2 'Licensed and insured'
console.log(r.summary);
Python · ffn_verify
from ffn_verify import verify_business

REGISTRY = {"origin": "https://registry.fofo.network", "name": "Sweet Papa Technologies LLC"}
result = verify_business("acme-hvac.com", registry=REGISTRY)
if result["verified"]:
    print(result["level"], result["levelName"])

HTTP API

Free and rate-limited. All responses are public facts; private evidence never leaves the registry.

Request Returns
GET /v1/lookup?domain=… The signed record for the business that owns the domain, or 404.
GET /v1/lookup?phone=… The signed record for the business whose verified phones include the number, or 404.
GET /v1/businesses/{id} The signed record by its ID.
GET /v1/businesses/{id}/evidence JSON: each fact's state and reason, and each check's source, result and date.
GET /v1/audit?domain=… The agent-readiness audit as JSON (also at /audit as a page).
GET /.well-known/did.json The registry's DID document, with the key that signs records and facts.

The signed record

  • A JWT with media type application/ffn-business-record+jwt, signed by the registry and valid for two days.
  • It carries the profile the business signed, the delegation that lets the registry publish it, the registry's attestations (entity, official channels, license, insurance, representative) and recent revocations with reasons.
  • Each attestation carries its checks: what was checked, against which source, by an automated check or a reviewer, the result and the date.
  • Facts can be suspended (a lapsed binding or insurance) or withdrawn, always with a reason code a verifier can read.

Domain binding

Each listed domain points back to the registry entry in two ways:

  • https://<domain>/.well-known/did.json, a DID document listing the business key, with a service entry of type FfnVerifiedBusiness naming the registry record. A secondary domain names the primary DID in alsoKnownAs.
  • A DNS TXT record at _ffn.<domain>: v=ffn1; did=<did>; registry=<registry host>.

A business with only the DNS record is listed with a lower-assurance binding, and verifiers report it.

Pages for people

Every listed business has a public profile at /b/<domain>, with the same facts in schema.org JSON-LD for crawlers. It points to the signed record, which is the thing to verify. The sitemap lists every profile.