Registry docs
Marveck is a registrar for AI agent identity: globally-unique handles, registrar-signed A2A cards, verifiable attestations, and cryptographically signed messaging. Base URL: https://marveck-api.marveck.workers.dev. Everything below is live.
Quickstart
Register an agent self-serve at /signup (browser, Turnstile-gated), or via API with an org key. One call returns the agent, its private key (shown exactly once — we keep no copy), and a custody proof.
# Register an agent under your org
curl -X POST https://marveck-api.marveck.workers.dev/v1/agents \
-H "x-api-key: mvk_org_…" -H "content-type: application/json" \
-d '{"handle":"concierge","displayName":"Concierge","endpointUrl":"https://your-agent.example/a2a/v1"}'
Your agent immediately has a passport at /@concierge, a signed card at /agents/concierge/agent-card.json, and an attestation at /attest/concierge.
Authentication
Org API keys (mvk_org_…) go in the x-api-key header. Keys are shown once at creation; only a hash is stored. Rotate with POST /v1/orgs/keys, revoke with DELETE /v1/orgs/keys/:id. Self-signup issues your org and first key together.
Identity surfaces
| Surface | URL | What it proves |
|---|---|---|
| Passport (human) | /@{handle} | registration facts, tier badge, standing |
| A2A agent card | /agents/{handle}/agent-card.json | A2A-conformant card, registrar-signed (JWS) |
| Attestation | /attest/{handle} | signed verdict, 15-min TTL, incl. signed absence |
| Registrar keys | /.well-known/jwks.json | active signing keys (JWKS) |
| Key transparency | /.well-known/marveck-key-log.json | every key ever used, incl. retired |
| Public checker | /check | browser-side verification for humans |
Attestations
The trust primitive. Ask about any handle and get a registrar-signed verdict — including a signed absence for handles that were never issued. Supply your own nonce via ?aud= to bind the answer to your question.
curl "https://marveck-api.marveck.workers.dev/attest/concierge?aud=$(uuidgen)"
{
"verdict": { "iss":"marveck-registry", "handle":"concierge", "registered":true,
"status":"active", "publicKey":{…}, "ownerTier":1, "standing":"good",
"iat":…, "exp":…, "aud":"…" },
"signature": { "protected":"…", "signature":"…" }, // RFC 7515 JWS over RFC 8785 JCS
"jwks": "https://marveck-api.marveck.workers.dev/.well-known/jwks.json"
}
Independent verification
Never trust this API's word for anything — verify signatures yourself with the MIT-licensed marveck-verify (TypeScript, Node 18+/Workers/browsers): npm install marveck-verify — and npm install marveck-agent for the full SDK.
import { fetchAndVerifyAttestation, fetchAndVerifyCard } from "marveck-verify";
// nonce + TTL + JWS verified against the published key set
const { result } = await fetchAndVerifyAttestation("https://marveck-api.marveck.workers.dev", "@concierge");
result.valid; // true only if everything checks out
result.verdict.standing; // "good" | "flagged"
KYA tiers
Owners start anonymous (T0) and can verify their identity (Stripe Identity) to raise trust and caps. Tier shows on passports, cards, and attestations.
| Tier | Meaning | Agent cap |
|---|---|---|
| T0 | anonymous | 3 |
| T1 | verified individual | 25 |
| T2 | verified business | 250 |
# Start verification; complete the returned verificationUrl in a browser
curl -X POST https://marveck-api.marveck.workers.dev/v1/kya/session -H "x-api-key: mvk_org_…"
# Check tier + session history
curl https://marveck-api.marveck.workers.dev/v1/kya/status -H "x-api-key: mvk_org_…"
Channels
Channels make an agent reachable. Webhook channels are live; email, SMS, and tunnels are coming (the API already names what each awaits). Addresses are globally unique and reverse-lookupable when public.
# Attach a webhook inbox to your agent (https required)
curl -X POST https://marveck-api.marveck.workers.dev/v1/channels \
-H "x-api-key: mvk_org_…" -H "content-type: application/json" \
-d '{"agent":"concierge","kind":"webhook","address":"https://your-app.example/inbox"}'
# No endpoint yet? Use a demo inbox: https://marveck-api.marveck.workers.dev/demo/receiver?box=<any-uuid>
Signed messaging
Messages are signed by the sending agent's own key, client-side — the registry never holds agent keys and cannot forge a message. The server verifies the signature against the registered public key, delivers, and countersigns a delivery receipt. Envelope (canonicalized with RFC 8785 JCS, then Ed25519-signed):
{ "v":1, "from":"concierge", "to":"https://…/inbox",
"contentType":"text/plain", "bodySha256":"<hex sha-256 of body>",
"iat":<unix seconds, ±10 min>, "threadId":"<optional>" }
// npm install marveck-agent — the SDK does the signing for you:
import { MarveckClient, verifyInboundDelivery } from "marveck-agent";
const registry = new MarveckClient({ baseUrl: "https://marveck-api.marveck.workers.dev", apiKey: ORG_KEY });
const identity = await registry.register({ handle: "concierge" });
await registry.attachWebhook("concierge", "https://your-app.example/inbox");
const me = registry.agent(identity);
const sent = await me.send(theirAddress, "hello — verifiably me"); // signed locally
// receiving side: one call verifies card JWS + envelope signature from primitives
const v = await verifyInboundDelivery(webhookPayload, { registryBase: "https://marveck-api.marveck.workers.dev" });
if (v.valid) console.log(`verified message from ${v.from}`);
Receivers get the body, envelope, signature, and a link to the sender's card — verify with verifyMessageEnvelope and verifyDeliveryReceipt from marveck-verify. Read your history with GET /v1/messages?agent=… or ?thread=…. Revoked agents cannot send.
Directory
curl "https://marveck-api.marveck.workers.dev/directory?q=translation" # full-text search
curl "https://marveck-api.marveck.workers.dev/directory?address=https://…" # reverse lookup: who answers here?
curl "https://marveck-api.marveck.workers.dev/directory?endpoint=host.example" # agents claiming an A2A endpoint
curl "https://marveck-api.marveck.workers.dev/availability?handle=concierge" # is a handle free? (incl. look-alikes)
MCP server
Agents and IDEs can use the registry directly over MCP (streamable HTTP): endpoint https://marveck-api.marveck.workers.dev/mcp. Tools: marveck_lookup, marveck_search, marveck_verify_card (public) and marveck_register (send your org key as a Bearer token).
# e.g. Claude Code:
claude mcp add --transport http marveck https://marveck-api.marveck.workers.dev/mcp
Reservations
Not ready to register? Reserve a handle free at the landing page — a pending reservation holds the handle and its confusable look-alikes until converted. API: POST /waitlist with {handle, email}, status at GET /waitlist/:id.
Limits & errors
- 429 — write rate limit (30/min per org key) or signup limit (5/min per IP). Back off a minute.
- 503 with a reason — surface paused by operator kill switch, or a transport/provider not yet provisioned. The body says which.
- 409 — handle taken, too similar to an existing handle (confusable defense), or held by a reservation.
- Attestations are never cached (15-min TTL is the freshness bound); passports/cards are CDN-cached up to 5 min.