Parafé · Docs · Same guide as plain text: parafe.ai/llms.txt

Parafé

Parafé is a neutral trust broker for agent-to-agent interactions. It gives an AI agent a verifiable identity, runs mutual authentication between two agents, issues scoped consent tokens, and signs receipts of what happened. This file tells an AI agent how to get a Parafé identity on its own, get it claimed by the person it acts for, keep it renewed, and use it in a handshake.

This guide as a web page: https://parafe.ai/docs/agents
Start here: https://api.parafe.ai/ (JSON: where everything is; a web page in a browser)
Broker API: https://api.parafe.ai (OpenAPI: https://api.parafe.ai/openapi.json)
Portal (for people): https://platform.parafe.ai
A2A extension spec: https://parafe.ai/extensions/a2a/v2
Reference (every field on accounts, organizations, agents and passes, in plain language): https://parafe.ai/docs/reference
SDK (Node/TypeScript): https://www.npmjs.com/package/@getparafe/sdk (covers everything below; waitForClaim() waits for step 4)
Every API error is JSON: { "error": "<code>", "message": "…" }. The table at the end says what to do for each code.

Before you start

1. Make a key pair

P-256 (ES256) is recommended: it is the only type that can sign AP2 payment receipts, which shops may ask for. Ed25519 is also accepted. Keep the private key. Send the public key as base64 SPKI (DER) or as a public JWK.

2. Register

POST https://api.parafe.ai/agents/register
Content-Type: application/json
Parafe-PoP: <proof JWT signed with your new private key>
{ "public_key": "<base64 SPKI or JWK>" }

The proof shows you hold the key you're registering (nobody can register someone else's key). It's the same kind of proof as in step 3: header { "typ": "parafe-pop+jwt", "alg": "ES256" } (or "EdDSA" for Ed25519), claims "htm": "POST", "htu": "https://api.parafe.ai/agents/register", "iat" (now), "jti" (random, new each time). The SDK and MCP server sign it for you.

That is all you need. Your public name is your agent_id. Optional:

Both are shown only to the person on the claim page, marked as what you said. They are not verified, not public, and not in your credential. So the 201 response shows agent_name as your agent_id and principal_name as null: that's expected, what you sent is kept for the claim page.

201 response (store all of it). If this key already has an agent you registered without an API key, you get that agent back instead (200, "existing": true, with its pending claim link). A key another agent uses is refused (409 key_in_use), and so is a revoked agent's key (409 key_revoked): make a new key pair.

{
  "agent_id": "prf_agent_…",
  "did": "did:web:api.parafe.ai:agents:prf_agent_…",
  "identity_assurance": "self_registered",
  "verification_tier": "unverified",
  "credential": "<JWT>",
  "credential_sd_jwt": "<SD-JWT VC>",
  "expires_at": "…",
  "claim": { "claim_url": "https://platform.parafe.ai/claim?code=7KQ2-M9XD-4H", "code": "7KQ2-M9XD-4H", "expires_at": "…" }
}

3. Authenticate as yourself: credential plus proof of possession

Every request you make as the agent sends two headers:

Authorization: Bearer <credential>
Parafe-PoP: <proof JWT>

The proof is a JWT signed with your private key:

A proof is valid for 5 minutes and only once.

4. Get claimed by the person you act for

Show the person the claim_url and tell them its code, for example: "To let shops trust me with orders, please open this link and approve me: <claim_url>. The page will show the code 7KQ2-M9XD-4H." They sign in to Parafé (or create an account), check that the page shows the same code, and approve or reject. The page says "Platform: Unknown (self-registered)" (Parafé names a platform only when it authenticated it) and shows what you said about yourself. The person can give you a name that only they see.

Then wait for the approval. Ask, and the broker answers the moment they approve (or after wait seconds):

GET https://api.parafe.ai/agents/{agent_id}/claim-status?wait=25   (credential + a new proof each time)
→ { "claimed": true, "identity_assurance": "claimed", "verification_tier": "unverified", "principal_tier": "unverified", "credential_current": false, "principal_type": "personal", "operator_type": null, … }

Your new identity counts in handshakes from the moment they approve. Renew next (step 5): credential_current is false after a claim.

5. Renew

POST https://api.parafe.ai/agents/{agent_id}/renew (credential + proof, no body)

Renew when:

If your credential has already expired (less than a year ago), renew anyway with the expired credential and a proof (reason expired): renewal is the one thing an expired credential can still do.

The response has a new credential and credential_sd_jwt. Use them from now on, and save them where you keep your identity: the old credential stops working.

6. Handshake with another agent

Read the target's A2A agent card (https://<domain>/.well-known/agent-card.json) for its Parafé agent_id and each scope's requirements. Then:

POST https://api.parafe.ai/handshake/initiate (proof claims: target_agent_id, requested_scope)
{ "initiator_credential": "<credential>", "target_agent_id": "prf_agent_…", "requested_scope": "place-order",
  "authorization": { "modality": "autonomous" } }

Send the returned challenge to the target as described in the A2A extension spec. The target completes the handshake and you get a consent token for the scope.

If the target requires more than you have, the broker answers 403 with a code (table at the end). For identity_insufficient or tier_insufficient, while no person has claimed you, that answer includes:

{ "claim": { "claim_url": "…", "code": "…", "expires_at": "…" }, "hint": "Ask the person you act for to open this link to verify you, and tell them its code." }

Pass the link to your person, wait for approval (step 4), renew if needed (step 5), and try again. If a person already claimed you and you are refused for tier, your person needs to verify their email (https://platform.parafe.ai/verification).

For authorization_insufficient, the answer says what the scope needs: required_modality, provided_modality and a hint; for delegated and verified, also trusted_issuers (the mandate issuers the target trusts) and mandate_requirements (what the mandate must name). Never claim a modality you can't back: attested means the person you act for asked for this; delegated and verified need a mandate they signed.

7. Receipt what you do

When the other agent returns action receipts for what it did or refused for you (action_receipts in its reply, A2A extension spec section 4.5), file your copies so it is on the session's record even if that agent doesn't:

POST https://api.parafe.ai/sessions/{session_id}/action-receipts (credential + proof, claims: session_id)
{ "receipt": "<one action receipt JWS, exactly as received>" }
→ 201 { "seq", "acknowledgment", … }, or 409 `duplicate_receipt` with the same acknowledgment if it is already filed.

When you are the one acting, sign your own action receipt (spec section 5.2) and file it the same way. File before anyone closes the session: the session receipt lists every filed receipt. The @getparafe/sdk does both: recordActionReceipt(), fileActionReceipt().

8. Close the session and keep the receipt

When you're done, close the session. Either participant can:

POST https://api.parafe.ai/session/close (credential + proof, claims: session_id)
{ "session_id": "sess_…" }
→ 200 { "format_version": 2, "receipt_id", "session_id", "receipt": "<JWS>", "claims": { … } }

The receipt is a JWS the broker signed: who took part, what was consented to, and every filed action receipt. Keep it, and give it to your person if they ask what happened. Verify it with the broker keys (kid in its header). Either participant can fetch it again later:

GET https://api.parafe.ai/sessions/{session_id}/receipt (credential + proof, claims: session_id)

Reference

What to do when refused

CodeWhat it meansWhat to do
unauthorizedNo credential sentSend Authorization: Bearer <credential> (step 3).
invalid_credentialCredential expired, revoked or not yoursRenew (step 5); if renewal is refused too, you may have been revoked: register again and get claimed.
proof_requiredNo Parafe-PoP proofSign one for this request (step 3; for registration, step 2).
proof_invalidThe proof doesn't match the requestCheck htm, htu (full URL, no query), iat (now), the route's claims, and that you signed with your registered key.
proof_replayedThat proof was already usedSign a new proof (new jti) for every request.
agent_inactiveYou were revoked or suspendedStop. Tell your person; they can register a new agent.
key_in_useAnother agent already uses this keyMake a new key pair and register again.
key_revokedThis key belonged to a revoked agentMake a new key pair and register again.
already_claimedA person already claimed youNothing to do: check claim-status.
identity_insufficientThe scope needs a stronger identityShow your person the claim link in the answer (step 4).
tier_insufficientThe scope needs a more verified personNot claimed: the claim link. Claimed: your person verifies their email, then you renew.
authorization_insufficientThe scope needs a stronger authorizationRead required_modality, hint, trusted_issuers, mandate_requirements (step 6).
initiator_proof_insufficientThe scope needs a proof of possessionSend the Parafe-PoP header with the handshake.
tenure_insufficient, completion_rate_insufficient, denied_requests_exceeded, counterparties_insufficient, handshake_success_rate_insufficientYour track record is below the scope's floorUse a scope with lower requirements, or build history first. The answer has required and actual.
permissions_not_in_scopeYou asked for permissions the scope doesn't grantAsk only for scope_permissions from the answer.
scope_not_foundThe target doesn't offer that scopeRead its agent card or GET /agents/{id}/scope-policies.
no_trusted_issuersThe target trusts no mandate issuer for this scopeYou can't get delegated or verified here; tell your person.
mandate_invalid, mandate_mode_mismatch, mandate_payee_mismatch, mandate_agent_mismatch, mandate_signed_by_agentThe mandate doesn't fitRead message (and reason); get a new mandate from your person that meets mandate_requirements.
mandate_already_redeemedThat mandate was usedGet a new one.
expiredThe handshake took too longStart a new handshake.
not_participantThat session isn't yoursUse your own session_id.
already_closedThe session is closedFetch the receipt (step 8).
validation_errorThe request is malformedRead message.
not_foundNo such route, agent or sessionCheck the ID; for routes, start at https://api.parafe.ai/.
rate_limited / HTTP 429Too many requestsWait, then retry less often.