Verified by NPC

For developers

The signed record, from your own code.

The Verified by NPC API is live at api.npclabs.xyz. Register the agents and content you ship, look their records up from your own application, and check NPC's signatures yourself, against keys NPC publishes. No API key is needed, and registration is free.

What you can build

Put an agent on record

Register an agent you run and get a signed record with its own NPC ID, issued on the spot. The record names the agent's accountable owner and states what has been checked and what has not.

Put content on record

Register an image, text, audio, video, or other content, by web address or by content hash. The answer is the same kind of signed record, ready to cite wherever the content travels.

Look any record up

One call resolves an NPC ID to its signed record: registrations, credentials, products, and agents. An ID with no record answers unknown, plainly, and never a guess.

Check the signature yourself

Every record is signed with Ed25519, and the public keys are published. Your code can confirm a record came from NPC and has not been changed, without calling NPC at all.

Quickstart

Every call below is real. The examples were run against the live API while this page was written, and the records they made are live records you can look up.

1. Check the service.

curl https://api.npclabs.xyz/v1/health
{ "chain": { "anchoring": "disabled", "mode": "local-first", "network": "none", "note": "Phase 1 records anchor hashes locally; no chain writes until the mainnet gate clears." }, "key_id": "npc-demo-api-signing-20261014-e9c73a", "status": "ok", "time": "2026-10-16T02:35:14+00:00", "version": "1.0.0" }

2. Register an agent. An agent registration names the agent and its accountable owner. A homepage or a description is required. The owner's email is required too, and it never appears in the public record.

curl -X POST https://api.npclabs.xyz/v1/register/agent \ -H "Content-Type: application/json" \ -H "Idempotency-Key: api-docs-example-2026-10-15" \ -d '{ "agent_name": "Docs Example Agent", "owner_name": "NPC Labs", "owner_email": "hello@npclabs.xyz", "description": "An example agent registered to document the Verified by NPC API." }'

The answer, status 201, is the signed record, issued on the spot:

{ "record_id": "reg_6789fb4ca0f5363853a23dc0", "record_type": "npc.registry.agent_registration", "kind": "agent", "agent_name": "Docs Example Agent", "owner_name": "NPC Labs", "description": "An example agent registered to document the Verified by NPC API.", "homepage": null, "status": "registered_checks_pending", "status_label": "registered, checks pending", "registered_at": "2026-10-16T02:35:35+00:00", "checks_run": [ { "check": "named_owner", "status": "recorded", "detail": "The registration names an accountable owner, as the registry requires. NPC records the owner; it does not operate the agent." }, { "check": "registration_claim", "status": "issued", "detail": "This signed claim records the registration of the agent. Registration is not verification." } ], "checks_not_run": [ { "check": "scope_review", "reason": "The agent's declared scope of authority has not been reviewed yet." }, { "check": "human_review", "reason": "A person has not reviewed this registration yet." }, { "check": "verification_decision", "reason": "Registration is not verification. No verification decision has been made, and no verification mark is issued at registration." } ], "key_id": "npc-demo-issuer-20261014-727fb5", "signature": "/gfFVDAqu3QufnzSM/K3RaMARDFysuAc4NiyYjAaVhfugGI1KryI7y03UroMjePTZuDLucmNRDsJnAw4rUAMBQ==" }

The status says what the record is: registered, checks pending. Registration is the start of verification, not the result, and no verification mark is issued at registration. The record itself lists the checks that ran and the ones that have not.

3. Register content. The kind is one of image, text, audio, video, or other. The locator is a web address where the content can be fetched, or its SHA-256 hash, written as sha256: followed by the hash. Content at a web address is fetched once at intake, and its SHA-256 is recorded. This example registers by hash, so the record carries the hash the creator provided:

curl -X POST https://api.npclabs.xyz/v1/register/content \ -H "Content-Type: application/json" \ -d '{ "title": "API documentation example text", "kind": "text", "locator": "sha256:6f64362c5920bee25236a3bd0783160665cf0b3c370946b5bbd20e94d2862da3", "creator_name": "NPC Labs", "creator_email": "hello@npclabs.xyz" }'
{ "record_id": "reg_d8b68b02eb095431acc031d2", "record_type": "npc.registry.content_registration", "kind": "content", "content_kind": "text", "title": "API documentation example text", "locator": "sha256:6f64362c5920bee25236a3bd0783160665cf0b3c370946b5bbd20e94d2862da3", "locator_kind": "content_hash", "creator_name": "NPC Labs", "status": "registered_checks_pending", "status_label": "registered, checks pending", "registered_at": "2026-10-16T02:35:41+00:00", "checks_run": [ { "check": "content_hash", "status": "provided_by_creator", "detail": "The creator provided this content hash. NPC has not seen the content itself.", "locator": "sha256:6f64362c5920bee25236a3bd0783160665cf0b3c370946b5bbd20e94d2862da3" } ], "checks_not_run": [ { "check": "human_review", "reason": "A person has not reviewed this registration yet." }, { "check": "verification_decision", "reason": "Registration is not verification. No verification decision has been made, and no verification mark is issued at registration." } ], "key_id": "npc-demo-issuer-20261014-727fb5", "signature": "AfnTGvaj84XJSTvRoy9RHlkRVEF6lMtatt3gwU+0B67kfpuRKtlcDVdtcRNOecqau/1B+RG6jeeRSzC5cDfIAA==" }

For an image, intake also reads the image's C2PA content credentials, recording whether they are present and how they are structured, and records an AI-generation signal as a percentage with its uncertainty stated. A signal is information, not a verdict, and the record says which is which.

4. Look a record up. The same record answers at its own address, and Search on this site resolves the same IDs:

curl https://api.npclabs.xyz/v1/records/reg_6789fb4ca0f5363853a23dc0

An ID with no record fails closed:

curl https://api.npclabs.xyz/v1/records/reg_000000000000000000000000 404 {"verdict": "unknown"}

5. Check the signature. Records carry their signature inside them, and every API response carries one in its headers: X-NPC-Signature, with the signing key named by X-NPC-Key-ID. The public keys live at one address:

curl https://api.npclabs.xyz/v1/keys

The current keys, from that document. Retired keys are listed there too, marked retired, so older records stay checkable:

{ "api_signing": { "current": { "algorithm": "Ed25519", "key_id": "npc-demo-api-signing-20261014-e9c73a", "public_key": "sl7vwSgymgvrTaHg8l4FIKAPzoSYvXLH3Jm2zj/Ji/A=", "status": "active", "created_at": "2026-10-15T04:26:54+00:00", "retired_at": null } }, "issuers": [ { "algorithm": "Ed25519", "key_id": "npc-demo-issuer-20261014-727fb5", "public_key": "9keaHrMrvoaLX9kvl/3l7pagM91FOrlCC6EPJv1VYfA=", "status": "active", "created_at": "2026-10-15T04:26:54+00:00", "retired_at": null } ] }
  1. Find the key. Take the record's key_id and find that entry in the keys document.
  2. Canonicalize. Remove the signature field, then write what is left as NPC-JCS-v1: UTF-8, keys in sorted order, no extra whitespace.
  3. Verify. Check the base64 Ed25519 signature against that entry's public key.

The example record above passes this check, and changing any field in it makes the check fail.

The MCP endpoint

If you build with agents, the same records are one connection away. NPC runs a hosted MCP server at https://api.npclabs.xyz/v1/mcp. Point an MCP client at that address:

{ "mcpServers": { "npc-verify": { "url": "https://api.npclabs.xyz/v1/mcp" } } }

Its tool list answers today with seven tools. Four verify against the records (verify_claim, verify_credential, verify_product, verify_agent), one explains an answer in plain words (explain_verification), and two register from inside the conversation (register_agent, register_content):

curl -X POST https://api.npclabs.xyz/v1/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }'

Prefer to run the server yourself: the same tools ship on PyPI as npc-verify-mcp, version 1.0.1.

pip install npc-verify-mcp

Good to know

Which surface should you use?

SurfaceFitsUse it when
REST APIYour own application or serviceYou want registration and record lookups inside your own code.
Hosted MCPAgent frameworks and MCP clientsYou want an agent to ask, and to register, as it works, with no server of your own to run.
npc-verify-mcpYour own infrastructureYou want to run the MCP server yourself, against the same live API.
PluginsChatGPT, Gemini, and other assistantsYou want NPC checks inside an assistant your users already open. See the Plugins page.

Questions about building on the API: hello@npclabs.xyz.