Skip to main content
Version: v0.2

Behavior rules

This page collects the normative MUST and SHOULD requirements that an AAP-compliant agent must follow. These rules are the bare minimum for interoperability and regulatory compliance; they are referenced from the per-skill pages and applied by the dealer-side test suite.

The keywords MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, RECOMMENDED, and OPTIONAL are interpreted as in RFC 2119.

Inventory rules

Inventory MUSTs

  • Inventory feeds MUST contain only in-stock statuses. Vehicle.status is a controlled enum: available | intransit | pending. Dealer agents MUST only return vehicles whose status is one of these three in inventory.search results. A vehicle in any other state is OUT OF STOCK: the dealer MUST omit it, and a buyer agent that somehow observes any other value MUST ignore the vehicle and treat it as unavailable. status is REQUIRED on every inventory listing.
  • updated_at is MANDATORY for availability claims. Every Vehicle returned by inventory.search and inventory.vehicle MUST include updated_at whenever the agent is making availability claims about the listing. The field is an RFC 3339 timestamp indicating when the dealer last updated this listing's availability, price, and status.
  • vehicle.vin or vehicle.stock SHOULD be present on detail responses. inventory.vehicle responses SHOULD include vin or stock. When neither is present (e.g. a deeply pre-allocated unit), the response MUST include vehicle_id and SHOULD include free-text notes explaining the unit's identification.
  • When implemented, inventory.search MUST support anonymous calls. A dealer agent is not required to expose inventory.search, but if it does, it MUST accept calls without customer info and without consent. AAP RECOMMENDS dealer agents publish their search surface anonymously by default when they expose one.

Inventory SHOULDs

  • Dealer agents SHOULD update updated_at no less frequently than once per business day for each in-stock listing.
  • Dealer agents SHOULD echo the request's pagination.skip and pagination.limit in the response data.skip and data.limit so buyer agents can paginate without ambiguity.
  • Buyer agents SHOULD attach privacy.anonymous: true to every inventory.search call by default and only attach customer identity when actually submitting a lead.

Lead rules

Consent gate: anonymous inventory access vs consent-gated lead access

Lead MUSTs

  • customer is REQUIRED on every lead.submit request. The unified lead is never anonymous. Every lead.submit.request MUST include a customer block; the schema enforces this in required.
  • consent is MANDATORY whenever customer is present (which is always for lead.submit). Every lead.submit.request MUST include a consent (ConsentGrant) block. A request that violates this MUST be rejected with CONTACT_CONSENT_REQUIRED.
  • Channel must be permitted. Dealer agents MUST reject the lead with CONTACT_CONSENT_REQUIRED if the requested follow-up channel (or the channel implied by customer.preferred_contact) is not in consent.allowed_channels[]. The dealer MUST NOT use a channel the user did not authorize.
  • Buyer agents MUST NOT include phone or email without explicit user authorization. A buyer agent MUST capture an explicit consent action from the user — verbatim text shown, channels selected, scope confirmed — before populating customer.email, customer.phone, or customer.address. The verbatim text MUST be reproduced in consent.consent_text.
  • Scope is fixed. consent.scope[] MUST be ["lead_submission"]. A ConsentGrant whose scope is anything else MUST cause the dealer to reject with INVALID_CONSENT.
  • Condition vocabularies MUST NOT be mixed. vehicle_of_interest.condition (when set) MUST be one of new | used | cpo. trade_in.condition (when set) MUST be one of excellent | good | fair | poor. Mixing these MUST be rejected with SCHEMA_VALIDATION_FAILED (the conditional schema enforces it) or INVALID_CONDITION.

Lead SHOULDs

  • Dealer agents SHOULD return status: "duplicate" (instead of received) when the same customer submits an equivalent lead within a short window (dealer-defined; commonly 24 hours).
  • Dealer agents SHOULD include a brief message on every successful lead response explaining the next step (e.g. "A sales rep will email Anna within 1 business day.").
  • Dealer agents SHOULD persist the full ConsentGrant JSON as an audit record alongside the lead. ADF mapping does not specify a consent element; the ConsentGrant is the AAP-side record.
  • Buyer agents SHOULD bundle vehicle_of_interest, trade_in, and appointment into a SINGLE lead.submit.request when they belong to the same shopping intent, rather than making multiple consecutive submissions. This keeps the dealer CRM transactional and avoids re-stitching one customer intent.

Appointment rules

Appointment MUSTs

  • Booking is not implied. A successful lead.submit response does NOT guarantee an appointment booking unless the data.appointment.status is confirmed. requested and proposed mean the customer has expressed interest but has not been booked.
  • Non-confirmable requests SHOULD return requested or proposed. When the dealer agent cannot auto-confirm a request (manual review required, the requested time does not fit, etc.), it SHOULD respond with data.appointment.status: "requested" or data.appointment.status: "proposed" rather than rejecting the appointment.
  • appointment_at MAY be omitted. When the buyer does not specify a time, the dealer SHOULD return requested and follow up to schedule. When present, appointment_at MUST be an ISO 8601 / RFC 3339 timestamp with a timezone offset.
  • vehicle_of_interest SHOULD be present for test_drive. When appointment.appointment_type is test_drive, the lead SHOULD also include vehicle_of_interest so the dealer knows which unit. A submission without vehicle_of_interest MAY be rejected with MISSING_REQUIRED_FIELD per dealer policy.

Appointment SHOULDs

  • The dealer agent SHOULD include the dealer's primary phone (data.dealer.phone, E.164) on every lead-with-appointment response so the buyer agent can surface it to the user.
  • The dealer agent SHOULD include data.appointment.confirmed_at on every confirmed appointment status and data.appointment.proposed_times on every proposed status.
  • Buyer agents that receive data.appointment.status: "proposed" SHOULD present the alternative times to the user and re-submit a fresh lead.submit with the chosen time in appointment.appointment_at.

Defaults and locale rules

When optional context fields are omitted, AAP defines deterministic fallbacks so buyer agents and dealer agents agree without out-of-band coordination.

  • Prices are integers in whole US dollars. msrp, list_price, offered_price, and price are plain integers in whole US dollars (e.g. 26780).
  • Address default country. Address.country is optional; when omitted, the assumed country is US.
  • Idempotency. Buyer agents that retry lead.submit after a network failure SHOULD pass an idempotency_key (UUID recommended). Dealer agents SHOULD dedupe on this key for at least 24 hours and return the original lead_id and status on retries.
  • Consent expiration. When ConsentGrant.expires_at is omitted, the dealer MAY apply its own default expiration window per local regulation; an explicit expires_at always wins. The dealer MUST reject the lead with INVALID_CONSENT if the grant has already expired.

Pricing rules

Pricing MUSTs

  • price MUST reflect the FINAL out-the-door amount. Vehicle.price is the FTC-final price the buyer would actually pay, including all incentives applied, all mandatory fees added, all required dealer add-ons added. Dealers MUST NOT advertise a price that omits required fees, conditions on dealer financing, or required add-ons. See Pricing and FTC compliance for the underlying FTC enforcement context (March 2026 warnings + CARS Rule).
  • price_min / price_max and sort.field: "price" apply to price. inventory.search filters.price_min, filters.price_max, and sort.field: "price" are evaluated against the price field, not list_price or msrp. Dealers MUST keep price accurate for the same reason.
  • offered_price is conditional on zip. Vehicle.offered_price MUST be omitted when no zip was supplied or when the dealer does not support desking. It MUST NOT be a substitute for price.

Pricing SHOULDs

  • Dealer agents SHOULD publish list_price, msrp, and price together for transparency. list_price is the base advertised number; price is the final out-the-door number; the difference is the sum of mandatory fees and required add-ons.
  • Buyer agents SHOULD compare offers across dealers on price (not list_price). Comparing on list_price deceives the user about the actual cost.

Authentication

AAP v0.2 defines no authentication of its own — agents are public by default. A dealer that needs to protect its endpoint uses A2A's native securitySchemes / securityRequirements on its agent card; obtaining and presenting credentials then follows A2A (a transport concern), not AAP. See Discovery.

Rate limits

  • Dealer agents SHOULD return RATE_LIMITED (HTTP 429 / JSON-RPC code -32002) with retryable: true and a hint in details.retry_after_ms when the buyer agent exceeds a per-key quota.

Ordering of rules

When two rules appear to conflict, the more restrictive one wins. For example: a vehicle whose status is not one of available | intransit | pending is out of stock and MUST NOT be returned as available, even if the dealer's own internal cache says otherwise. The buyer agent's choice of privacy.anonymous: true does NOT override the consent rules — those apply only to lead.* skills, where customer info changes the call.