Skip to main content
For engineers adding PACT to a personal agent. This is the happy path; the rules are in the specification. Any language works. In TypeScript, the reference client @openpactprotocol/client does steps 3–5. It is not on npm yet; copy packages/client/src/ from this repository.
Covers the PACT Identity profile only. Delegated authority is in spec §5.

Values you need

1 · Publish a signing key

Generate an ES256 key with a kid. Serve the public JWK as a JWKS at {PA_ISSUER}/.well-known/jwks.json. PA_ISSUER is your platform’s URL and becomes the iss claim. In this repository, pnpm gen-keys generates a key pair in this format. An example JWKS with one public key:
Publish only the public key. The private key has an extra d field; keep it secret and use it to sign tokens (step 3). Done when curl $PA_ISSUER/.well-known/jwks.json returns { "keys": [ … ] }.

2 · Get the Provider’s audience and register if required

Get the Provider’s audience from its documentation or onboarding process and copy it into aud (step 3). Do not derive it from the Agent Card URL. Registration depends on the Provider’s policy. If required, send your issuer and JWKS URL once per Provider, not per User or Brand. Open Providers may accept agents without prior registration and discover their keys instead. Both verify personal-agent JWTs in full (spec §3.1). The reference Provider requires registration and offers a self-service endpoint. Done when you have the Provider’s audience and have completed any required registration.

3 · Sign a personal-agent JWT

One per request, valid ≤ 300 s (spec §3.2): header kid; iss = PA_ISSUER; sub = your stable, opaque id for the User; aud = the Provider’s audience; iat, exp.
Done when jwtVerify(token, yourJwks, { issuer: PA_ISSUER, audience }) succeeds.

4 · Fetch the Brand’s Agent Card

No token. The interface URL is the url of the supportedInterfaces entry with protocolBinding: "HTTP+JSON" and protocolVersion: "1.0". A trimmed card (full example in spec §2.1):
interfaceUrl returns https://provider.example.com/a2a/01J… here. Step 5 sends to {interfaceUrl}/message:send.
Done when you have the interface URL. 404 means the Brand is unknown to that Provider.

5 · Send messages

POST {interfaceUrl}/message:send with Authorization: Bearer <token> and A2A-Version: 1.0 (spec §4). The reply carries a contextId; send it with every later message for the same User and Brand. Use a fresh messageId per message; resending one is a safe retry.
The agent may ask the User to prove who they are (order number, email); relay the question and answer. Done when the reply has role: "ROLE_AGENT" and a contextId, and a second message with that contextId continues the conversation.

6 · Handle errors

The reason is error.details[0].reason (spec §6). A2AClient throws A2AError for envelopes and A2AHttpError for the rest.

Test locally

Start the reference stack; it already trusts the demo key from pnpm gen-keys.
Done when steps 4–5 return a reply from Loom & Co. with a contextId. Delegated authority is optional: the User logs in with the Brand and approves scopes, so the Brand’s agent can act on their account. Brands advertise it on their card; spec §5 defines it. Nothing above changes.