Skip to main content
PACT builds on A2A 1.0, defining a verifiable identity for the personal agent sending each request (§3) and, optionally, the permissions the User grants it on their Brand account (§5). Transport, messages and errors follow A2A. The key words MUST, MUST NOT, SHOULD and MAY are to be interpreted as described in RFC 2119.

1 · Terms

2 · Transport

A2A 1.0 HTTP+JSON. Requests SHOULD send A2A-Version: 1.0 and Content-Type: application/json. A2A responses MUST use Content-Type: application/a2a+json.

2.1 Agent Card

One card per Brand, served by the Provider:
  • The personal agent gets the card URL from the Brand; it never builds it from a Brand ID. The standard place is https://{brandDomain}/.well-known/agent-card.json, which serves the card or redirects to the Provider’s URL. Out-of-band sources, such as a link from the Brand or a public registry of Agent Cards, MAY point to the card wherever it is hosted. This spec does not define a registry.
  • No authentication. An unknown brandId gets 404 with no A2A body.
  • MUST list a supportedInterfaces entry with protocolBinding: "HTTP+JSON" and protocolVersion: "1.0". Its url is the interface URL. Personal agents pick the interface by binding and version, not by position.
  • MUST declare the personal-agent JWT (§3) as an httpAuthSecurityScheme with scheme: "Bearer", bearerFormat: "JWT", listed alone in one securityRequirements entry.
  • MAY declare delegated authority (§5.1).
  • name, description, skills are informational.

2.2 Operations

Relative to the interface URL. Only message:send is required. Other A2A operations behave as A2A defines. Any route that isn’t an A2A operation gets 404 or 405 with no A2A body. Routing happens before authentication; an unknown Brand is 404 even with a valid token.

3 · Personal agent identity

The bearer token is a JWT the personal agent signs with its own key. The Provider verifies it against the personal agent’s JWKS. No shared secrets.

3.1 Registration

How these are exchanged is out of scope. Registration happens once per personal agent and Provider, not per User or Brand. audience is one value per Provider and MUST NOT be derived from a card URL. Whether a Provider accepts only personal agents it has allowlisted (a trusted-issuer registry) or any personal agent whose iss serves a JWKS is the Provider’s policy, not PACT’s. An open Provider still verifies §3.2 in full; jwksUri MAY then be found through OIDC discovery at {iss}/.well-known/openid-configuration.

3.2 Personal-agent JWT

Every request except the card carries Authorization: Bearer <pa-jwt>. Providers MUST verify the signature via jwksUri, allow at most 30 s clock skew, and reject unknown or disabled personal agents. The User is the pair (personal agent, sub); the personal agent MUST reuse the same sub for the same User.

3.3 What the personal-agent JWT proves

That a known personal agent is calling for someone it calls sub. Not that sub owns a Brand account. Without §5, the agent verifies the User the way it does in a chat widget (it asks for an order number, email, etc.) and the personal agent relays the User’s answers. Account credentials never pass through the personal agent.

3.4 Failure

For every authentication failure. No A2A body. Providers SHOULD authenticate before looking up the Brand or reading the body.

4 · Messages

4.1 Request

  • An A2A SendMessageRequest. configuration and metadata MAY be ignored.
  • role MUST be ROLE_USER. parts MUST have at least one non-blank text part. Other part kinds get CONTENT_TYPE_NOT_SUPPORTED.
  • taskId MUST be absent; otherwise TASK_NOT_FOUND.
  • messageId MUST be unique within the context.

4.2 Context

  • The reply is synchronous: { "message": Message } with role: ROLE_AGENT and contextId set (or a task, §5.5).
  • Without contextId, the message starts a new conversation and the Provider mints an opaque contextId.
  • With contextId, the message continues that conversation. The context MUST belong to this Brand and this (personal agent, sub); otherwise INVALID_PARAMS, without saying whether it exists for someone else.
  • contextId is state, not a credential. Ordinary turns create no A2A Task.
  • A Provider MAY close a conversation (the Brand’s agent ended it, or it expired). A message to a closed contextId gets UNSUPPORTED_OPERATION; the personal agent starts a new conversation by omitting contextId.

4.3 Retries

A repeated messageId in the same contextId returns the stored reply without re-running the agent. If there is no stored reply yet, return INVALID_PARAMS.

5 · Delegated authority

Optional. This is the PACT Delegated profile (§7). Identity (§2–4) works without it; Providers that don’t offer it omit §5.1 from their cards.
Lets the Brand’s agent act on the User’s Brand account, using standard OAuth 2.0 device code (RFC 8628). Each Brand defines its own scopes. The User logs in with the Brand, never with the personal agent, and approves some of them. The personal agent needs only a generic device-code client. In OAuth 2.0 terms: Delegated authority
  1. Request scopes. The personal agent asks the Provider for the scopes it needs, sending its §3 JWT as the client credential (§5.3).
  2. Login link. The Provider returns a link to the Brand’s own login. The personal agent shows it to the User and never handles the login itself.
  3. Sign in and approve. The User logs in with the Brand and approves scopes on the Provider’s consent page. The personal agent never sees the login.
  4. Delegation token. The Provider signs a delegation token listing the approved scopes (§5.4). The personal agent carries it but cannot change it.
  5. Send and receipt. The personal agent sends the token with each message. The Provider checks it, and the Brand’s agent acts as the User only within those scopes (§5.5). Every reply carries a signed receipt (§5.6).

5.1 Card

A Brand that supports delegation adds an oauth2SecurityScheme with a deviceCode flow and a second securityRequirements entry naming both schemes:
  • The entry that needs only the personal-agent JWT MUST stay. A personal agent MAY always talk with §3 alone.
  • oauth2MetadataUrl MUST serve RFC 8414 metadata; its jwks_uri publishes the keys that sign delegation tokens and receipts.

5.2 Scopes

A scope is { id, description }. Each Brand defines its own (orders:read, booking:change, whatever its agent does) and PACT reserves no ids. The Brand maps its agent’s capabilities to scopes; unmapped capabilities stay available under §3. Personal agents pick scopes by reading the descriptions and MUST request only ids on the card. Providers show descriptions to the User verbatim on consent.

5.3 Getting a token

RFC 8628 with two rules: the OAuth client is the personal agent, authenticated with its §3 JWT (client_id = its issuer URL); the login step is the Brand’s own login.
  • An unknown scope id gets OAuth invalid_scope. A bad personal-agent JWT gets 401 (§3.4).
  • The personal agent shows the User verification_uri_complete. It MUST NOT proxy, frame, or observe the login.
  • The link opens the Brand’s login. The Brand authenticates the User and returns the User to the Provider with a single-use assertion bound to the user_code, sent by POST, not a credential from another channel. The Provider then shows consent as the logged-in User: the personal agent’s issuer origin, the Brand, and each scope as a checkbox the User MAY uncheck. Login comes first so the grant is bound to a verified account.
  • Consent MAY be skipped when an unexpired grant for (User, personal agent) already covers the request.
Until approval: authorization_pending, slow_down, access_denied, or expired_token per RFC 8628. Then:
scope is what the User approved, which may be less than requested. The personal agent MUST read it.

5.4 Delegation token

access_token is a JWT signed by the Provider (ES256/RS256; keys at the jwks_uri from §5.1).

5.5 Sending with it

Both tokens go on the request. The personal-agent JWT is checked first, unchanged.
The Provider MUST (1) verify the personal-agent JWT (§3.2); (2) verify the delegation token’s signature, aud, exp, that client_id equals the personal agent’s iss, and that the grant is not revoked; (3) run the agent as Brand user sub, limited to scope. A bad delegation token gets 401 with WWW-Authenticate: Bearer realm="a2a", error="invalid_token", no A2A body. contextId rules (§4.2) are unchanged. A context started under §3 MAY continue under delegation. Once a context has run as one sub, a token for a different sub gets INVALID_PARAMS. Step-up. If a turn needs a scope the token lacks, the Provider MUST NOT fail it. It returns a task in TASK_STATE_AUTH_REQUIRED with the missing ids and a new link; the conversation stays open:
The personal agent repeats §5.3 for the missing scopes (login is skipped if the User’s session with the Provider is still live), gets a new token, and re-sends with the same contextId. The step-up task MAY be ephemeral; tasks/{id} MAY return TASK_NOT_FOUND for it.

5.6 Receipts

Every message:send served under a delegation token MUST include in the reply’s metadata a receipt signed with the same keys as the token:
jws is the compact JWS of claims. Personal agents SHOULD verify and keep receipts.

6 · Errors

A2A errors use the A2A / AIP-193 envelope. code repeats the HTTP status; the reason is error.details[0].reason. Clients MUST NOT infer the reason from the status alone.
INVALID_PARAMS covers: bad JSON or schema, wrong role, blank text, bad pageSize, an unknown or foreign contextId, a repeated messageId with no stored reply, and a sub mismatch (§5.5). Not A2A errors: 401 (§3.4, §5.5); 404/405 for unmatched routes or unknown Brands (§2.2); 429 with Retry-After when a Provider rate-limits a personal agent or a (personal agent, sub); and OAuth endpoint errors (RFC 6749 §5.2, RFC 8628). On 429, personal agents SHOULD wait Retry-After before retrying.

7 · Conformance

This is PACT 1.0. Breaking changes to either profile bump that number.

7.1 Implementing

Step-by-step guides with a check per step: Build a Provider (ends with running e2e/ against yourself with E2E_PROVIDER=any) and Build a personal agent integration.