Skip to main content
Version: 3.1.0

Versions and migration

AAP 3.1 adds explicit currency and odometer units. Existing omitted labels retain USD/mi meanings. Native Canadian amounts require the new fields and a 3.1 endpoint; do not relabel CAD/km numbers on an unchanged 3.0 endpoint. The frozen 3.0 contract remains unchanged.

Edit and verify the draft, freeze a new release, then publish and switch a verified deploymentOpen full-size diagram

Four independent version numbers​

IdentifierMeaning in AAP 3.1
AAP 3.1.0 / contract v3.1Automotive schemas, bindings and behavior
MCP 2026-07-28 + 2025-11-25Current wire protocol and explicit compatibility path
A2A 1.0Agent Card, Message and JSON-RPC protocol
PAP 0.3Pinned in-progress Poppy draft; discovery bridge remains version: "1"

A server's software version is separate. A PAP 0.2 client must migrate its authentication flow; a PAP 0.3 client is not automatically an AAP 3.1 client, and MCP version negotiation does not choose an automotive schema version.

AAP 3.0 to 3.1​

AreaExisting 3.0 meaningAdditive 3.1 behavior
Vehicle amountsWhole USDOptional currency labels USD or CAD; omission still means USD. It covers price, list_price, msrp and vehicle fees
Vehicle odometerMilesOptional mileage_unit labels mi or km; omission still means mi. Returned numbers remain native
Rooftop fee defaultsWhole USDOptional rooftop currency; omission still means USD. Never infer vehicle currency from it
Search and facetsUSD prices, mi odometer comparisonsOptional top-level currency and mileage_unit; use declared capability defaults, falling back to USD/mi. One currency scopes every matching set; mileage comparisons convert exactly
Facets without searchUSD/mi requests without search capabilitiesAccept explicit USD/CAD and mi/km contexts; omitted contexts remain USD/mi. No search capability declaration is needed
CapabilitiesNo monetary or odometer contextOptional currencies, default_currency, default_mileage_unit; declarations must agree across bindings
Results and cursorsUSD/mi implicitLabel effective nondefault contexts explicitly on search/facet data; bind both contexts into cursor identity. Per-vehicle labels never inherit query context
Geographic and electric rangeExplicit _mi fieldsUnchanged: miles for every country and odometer unit
Leads and trade-insUSD/mi if numeric values are presentPreserve explicit currency and odometer labels with each partial vehicle description

This requires schema, generated tool/OpenAPI metadata and runtime changes together. Documentation alone cannot establish the new fields or comparison behavior. Keep existing 3.0 and approved connector endpoints operating under their original contracts while publishing separate 3.1 discovery and endpoints. See currency and odometer context for exact defaults and comparison rules.

For implementers​

For implementations coming from 2.1, the 3.0 major migration below is also required. It made MCP native, added dealer-domain discovery links and search capabilities, and tightened automotive results and lead outcomes. Migrate the implementation and its clients before switching discovery. Keep each supported automotive contract at its own card and endpoint identity.

AreaAAP 2.1AAP 3.0 action
MCPReference manifest/optional adapterImplement native Streamable HTTP for both required revisions, actual tools/list and typed success/error results
Request headersA2A version and extension headers mandatoryAccept omitted A2A headers on contract-pinned endpoints and omitted MCP mirror headers when the body or this client's negotiated session supplies the value. Keep supplied-value conflict checks and all authentication requirements; see the binding pages for this AAP compatibility extension
PAPDraft 0.2 authentication and discoveryMigrate to draft 0.3 as detailed below; changing the version label is insufficient
DiscoveryA2A + PAP pairAdd complete AAP params, exact MCP URL, search capabilities, release metadata and dealer /llms.txt
Search filtersEmpty arrays, repeated values and empty queries can validateAdvertise supported keys/sorts; deduplicate arrays and omit empty optional filters. Reject make: [], make: ["Honda", "Honda"], empty/whitespace-only query, unknown keys and unsupported constraints; implement explicit query token rules
FeaturesFree-text attributesAdd features_all (AND), features_any (OR), advertised feature vocabulary and source-backed feature_evidence; unknown is not absent
GeographyLocation context without a radius contractIf advertised, implement near, haversine miles, radius filtering and distance_mi ordering
Coordinate names — breaking for deployed clientsSome deployment extensions accept near.lat / near.lng, including in validation-error hints; these were not AAP 2.1 schema fieldsUse near.latitude / near.longitude. Update handlers, client/tool schemas, examples and error hints together; AAP 3.0 rejects the short keys
PaginationOffset/limit; schema permits pagination.limit up to 1000Maximum falls to 100. Update clients requesting 101–1000 to use at most the advertised max_limit (never above 100) and follow next_cursor; total is exact or null; no silent result caps
Search responsedata.limit is optionalAlways return the effective data.limit, even when the client omitted it, plus next_cursor, applied_filters and effective sort; include query terms and distance/evidence when applicable
Aggregate sellerOpaque dealer_id without a lookupExpose dealer.information with a dealer_id selector; echo the same ID and actual seller profile before consent. Parameterless dealer-scoped requests remain valid
Inventory listingsSome guarantees only in proseRequire eligible status, updated_at and a stable identifier in search/detail responses
Lead retriesOptional key; duplicate is a lead statusRequire idempotency_key; retain atomic deduplication for at least 24 hours. Replay the complete original result with data.replayed: true, preserving received/rejected, appointment details and message. status: "duplicate" is removed
Contact channelsConsent declarationRequire matching contact data and an authorized preferred channel; reject unusable grants before delivery
Appointment outcomeSome conditions only describedEnforce time on confirmed and alternatives on proposed. Any appointment included on a rejected lead must also be rejected
ErrorsExisting automotive vocabulary; retry timing optional and may use secondsAdd DEALER_NOT_FOUND, UNSUPPORTED_FILTER, UNSUPPORTED_SORT, INVALID_CURSOR. RATE_LIMITED requires details.retry_after_ms; multiply seconds by 1,000. retry_after_seconds alone is insufficient. HTTP 429 also requires Retry-After
Error detailsaap.error.details accepts unrestricted JSON, including strings, arrays and nullWhen present, details must be an object. Convert custom diagnostics to details.errors[], where each item requires a JSON Pointer instanceLocation, a nonempty keyword and a nonempty error; additional detail fields remain allowed

The public DayHours and WeeklyHours TypeScript exports are retained. DayHours remains {open, close} | null; consumers keep their existing imports.

Pricing semantics, five canonical skill IDs, A2A 1.0 wire form and discovery bridge 1 remain. PAP upgrades to 0.3, including its breaking Session, metadata and optional-flow changes. Do not weaken authentication to make a client with missing credentials appear compatible.

Release order and version discovery​

  1. Publish the approved version-pinned specification, schemas and artifacts.
  2. Upgrade clients and server handlers, then pass runtime acceptance.
  3. Publish consistent Agent Card, Poppy and llms.txt links to the implemented endpoints.
  4. Switch the default discovery only when that complete contract works.

One A2A card declares exactly one required AAP extension. Several required versions do not express an either/or choice. A2A forbids automatic fallback to an earlier extension version.

For coexistence, retain separate version-specific cards and endpoints. One origin has one default well-known card; distribute other card URLs through explicit configuration or a registry, or use separate origins. For a coordinated cutover, communicate which clients must migrate and when the old endpoint retires. A new URI alone does not make retirement backward compatible.

Do not retry an uncertain lead through an older contract with a new key. Preserve its identity and reconcile the earlier outcome.

PAP 0.3 migration​

The target is the 0.3 draft at upstream commit 86f0c8d, reviewed 2026-10-26. This is not an upstream final release. Re-review later draft changes explicitly; do not silently follow a moving main.

SurfacePAP 0.2PAP 0.3 action
Discoveryprotocol_version: "0.2"Advertise "0.3" only after implementing it; unsupported pre-1.0 minors are incompatible
Redirected discoveryFinal-host identityAlso retain exact final /.well-known/poppy.json path without query
Issuer authorizationpoppy_domains: ["dealer.example"]Replace with protected_resources: ["https://dealer.example"]; no domain-entry port, path or slash; ignore hostname case only
Grant metadataJWT grant advertisement optionalRequire grant_types_supported, including JWT bearer and refresh_token, even for guest-only issuers
Sign-in discoveryauth.direct and auth.deviceRemove both; use authorization-code/device grants and their required metadata endpoints; any sign-in requires scopes_supported
ScopesBuilt-in poppy:read / poppy:write, plus auth.custom_scopesDefine company scopes; reserve all poppy: names. Replace with auth.scopes or listed OpenAPI OAuth descriptions; mediated scopes must be a supported subset
Scope hintsNo standard hintsOptional auth.scope_hints includes both changes and personal_data; unknown changes means irreversible, absent hints means unknown
Session identityCustom session_id in requests/responses; DPoP key could span Sessions for one UserRemove session_id. Create a new DPoP key per Session; key thumbprint identifies it. Renew with the same key, client, User and optional Agent ID
Session errorsinvalid_sessionUse invalid_grant; keep ended-key tombstones when possible; clients discard rejected ended keys and tolerate forgotten-key renewal creating a new Session
Token statesigned_in, guest scope: ""Remove both. Guest JWT grant always returns DPoP with scope omitted. Sign-in/Account Token grants are signed in; omitted scope means exactly as requested. Never infer state from scope presence
Agent identity within a UserNo Agent IDOptional pairwise opaque agent_id in Session assertion; unchanged or absent on renewal, no separate account/conversation ownership
Native MCP without DPoPToken issuance could return Bearer without a token-endpoint proofRequire RFC 8693 token exchange from a current DPoP Session Token; fresh token-endpoint DPoP still mandatory; return exact-resource Bearer and issued_token_type; never widen scopes
Native MCP with DPoPResource-bound DPoPContinue normal grants with DPoP and exact MCP resource. Wrong grant/token target gets invalid_target; never exchange to a DPoP-capable server
Direct Sign-InPKCE and Session IDBind code to Session Key via mandatory dpop_jkt support or proof on PAR; keep PKCE, state and response-issuer checks. Exchange with the same key
Native client redirectsSame-domain HTTPS onlyAlso permit RFC 8252 HTTP loopback IP literals, matching exactly except for port; remote identity fetches stay HTTPS
Device Sign-InDevice flowApply RFC 10027 protections; bind device code on first token poll, reject key changes
Browser joinSigned browser assertion and return URLReplace with browser-issued ≤60-second code, __Host- join cookie, Session-key DPoP nonce=code, one-use verification and required browser isolation headers
Account access errorsign_in_requiredUse insufficient_scope, including for signed-out requests; name required scopes and honor explicit sign-out
Token lifetime / revocationAccount Token expiry implicitOptional positive refresh_token_expires_in; revocation SHOULD invalidate issued Session Tokens; otherwise enforce state/short lifetime
Conversation messagessenderUse author: {type: "agent" or "human"}; Company authors may include id/name/image; authorization events require scope
Unavailable tasksFeedback only, 202Optional public excluded_tasks.url and alternatives; feedback clients accept 200 + alternative or 202 + no body; ignore references to unadvertised APIs
SecretsCredential protectionKeep tokens, private keys, authorization codes, PKCE verifiers and device codes outside model context; use trusted signing/sending code

Regenerate client/tool schemas and update TypeScript constructors with the new Poppy metadata and token shapes; the old fields are intentionally incompatible. The automotive request/response bodies and bridge 1 are independent of this change. Do not reset a lead's idempotency key during protocol migration or scope deduplication to a changing Session Key. Keep a stable verified caller/User identity and reconcile uncertain writes before changing authentication context.

PAP 0.2 migration​

This heading remains as a historical link. AAP 2.1 used PAP 0.2; its frozen migration record documents the earlier 0.1 → 0.2 transition. New AAP 3.1 implementations target 0.3 directly and apply all final identity, issuer-audience and proof requirements. They do not need an intermediate 0.2 deployment. The historical 2.0 → 2.1 minor-release exception was approved for one specification hash and does not relax the major-version policy.

Breaking migration checklist​

An upgrade from AAP 1.x must also apply the frozen 2.0 migration: paired PAP discovery and native API, required response contexts, standard A2A error detail arrays, securityRequirements shape, exact extension activation and truthful media types. Direct upgrades must implement the final contract in full; they need not deploy every intermediate version.

Editable work and stable releases​

Source or URLMeaning
spec/latest/, docs/Editable specification and documentation
/docs/latest/Editable documentation with an unreleased banner
spec/v3.1/, /v3.1/, /docs/v3.1/Frozen contract, artifacts and documentation after approval
/latest/Artifact alias of the stable release named by releases.json

Draft schema/extension URLs use https://draft.autoagentprotocol.invalid. Release preparation replaces them with immutable production identifiers. Agents pin the selected release rather than relying on a moving /latest/ alias.

SemVer and immutability​

AAP follows Semantic Versioning. Optional additive behavior can be minor; removed fields, tighter validation, changed required meanings or new mandatory interfaces require a major release. The structural compatibility report is conservative and does not replace semantic review.

Contract paths contain major/minor only, so the release tool creates MAJOR.MINOR.0 snapshots. Published snapshots are never edited, including their diagrams. Editorial corrections enter the editable source for a later release.

A release freezes schemas, examples, skills, docs/sidebar/images, generated TypeScript/OpenAPI/MCP artifacts, provenance, a compatibility report and SHA-256 integrity. CI and local checks reject changes under previously released paths. Historical artifacts are copied from their snapshots, never regenerated using newer tooling.

Preparing a release​

Commit reviewed edits to the working sources, then rehearse:

pnpm release:prepare 3.1.0 --dry-run

After reviewing the compatibility report, run without --dry-run from a clean tree. The command validates and freezes the new contract, generates artifacts, records the source commit/hashes and updates registry/package versions. It does not commit, tag, push, publish npm packages or deploy the site. See RELEASING.md.

A2A version handling​

Portable A2A clients send A2A-Version: 1.0 and the exact A2A-Extensions URI. AAP 3.0 additionally accepts their omission on a contract-pinned endpoint, using its configured A2A 1.0 interface and AAP contract. Supplied values still take effect: unsupported versions return -32009, and an explicitly empty version means 0.3, not a request for a default. This compatibility extension does not change strict upstream client requirements or permit automatic contract fallback. See request headers.