Skip to main content
Version: v0.2

lead.submit

A2A invocation

This skill is invoked through A2A's SendMessage operation (SendMessage JSON-RPC method or POST /message:send over HTTP+JSON), not a dedicated REST URL. The same payload travels on either A2A binding — see JSON-RPC binding or REST binding. AAP only defines what goes inside Message.parts[].data.

Consent gate: anonymous browsing on the left, ConsentGrant in the middle, consented lead on the right

The lead.submit skill is the single, unified lead-capture entry point in AAP v0.2. A buyer agent submits one request containing the consented customer plus any combination of vehicle_of_interest, trade_in, and appointment. This matches how dealerships actually take leads: a shopper test-driving a new car often wants their old car appraised in the same visit.

lead.submit replaces the early-draft trio of lead.general, lead.vehicle, and lead.appointment with a single contract.

PropertyValue
Skill idlead.submit
Request typelead.submit.request
Response typelead.submit.response
Anonymous allowedno
Consent requiredyes
ADF compatibleyes

For the field-by-field ADF/XML mapping, see ADF mapping.

Request shape

{
"type": "lead.submit.request",
"customer": { "...Customer..." },
"consent": { "...ConsentGrant... (scope MUST be ['lead_submission'])" },
"vehicle_of_interest": { "...Vehicle (condition: new|used|cpo)..." },
"trade_in": { "...Vehicle (condition: excellent|good|fair|poor)..." },
"appointment": { "...Appointment..." },
"message": "Free-text message from the user (max 4000 chars).",
"source_agent": "string (e.g. chatgpt-shopping)",
"submitted_at": "ISO-8601"
}
FieldTypeRequiredNotes
typeconstyeslead.submit.request.
customerCustomeryesBuyer contact info. Always required.
consentConsentGrantyesAlways required. scope MUST be ["lead_submission"].
vehicle_of_interestVehiclenoOptional. When present, condition (if set) MUST be new | used | cpo; vehicle MUST be identifiable via vin, stock, or year+make+model.
trade_inVehiclenoOptional. When present, condition (if set) MUST be excellent | good | fair | poor; MUST carry at least year+make+model. mileage is strongly recommended.
appointmentAppointmentnoOptional. appointment_type is one of sales | service | test_drive | trade_in; appointment_at is the requested start time (ISO 8601). The vehicle is implicit: vehicle_of_interest for a test drive, trade_in for a trade-in appraisal.
messagestringnoFree-text user note (max 4000 chars).
source_agentstringyesBuyer agent identifier (e.g. chatgpt-shopping, gemini-assistant).
submitted_atdate-timenoBuyer-agent timestamp at submission.

The unified Vehicle interface is the same shape used by inventory.search results — see the Vehicle schema source. Both vehicle_of_interest and trade_in use this shape; only the valid condition enum subset differs.

Response shape

{
"type": "lead.submit.response",
"data": {
"lead_id": "string",
"status": "received | duplicate | rejected",
"appointment": {
"appointment_id": "string",
"status": "requested | proposed | confirmed | rejected",
"confirmed_at": "ISO-8601",
"proposed_times": ["ISO-8601"]
},
"dealer": { "name": "string", "phone": "+1XXXXXXXXXX" }
},
"message": "Optional contextual note."
}
FieldTypeRequiredNotes
data.lead_idstringyesDealer-assigned lead identifier.
data.statusenumyesreceived, duplicate, or rejected. duplicate indicates the dealer recognized the same buyer/vehicle from a recent submission.
data.appointmentobjectconditionalPresent iff request had appointment AND the dealer is acknowledging it.
data.appointment.statusenum(when present)requested (manual review), proposed (alternatives in proposed_times), confirmed (booked at confirmed_at), or rejected.
data.dealerobjectnoConvenience contact summary the buyer agent can show the user.
messagestringnoOptional dealer note.

Full example: vehicle + trade-in + test-drive in one lead

A user wants to test-drive a 2024 Honda CR-V, trade in their 2020 Passat, and book Sunday afternoon. One request.

Request

{
"type": "lead.submit.request",
"customer": {
"first_name": "Piotr",
"last_name": "Nowak",
"email": "piotr.nowak@example.com",
"phone": "+14155555678",
"preferred_contact": "phone",
"address": {
"address_line_1": "320 Brannan Street",
"address_line_2": "Apt 412",
"city": "San Francisco",
"state": "CA",
"zip": "94107"
}
},
"consent": {
"granted_at": "2026-04-30T11:05:00Z",
"allowed_channels": ["email", "phone"],
"consent_text": "I authorize Demo Toyota to contact me by phone or email about VIN 1HGCY2F57RA000001, my requested test drive on May 3, and a possible trade-in of my 2020 Volkswagen Passat. I understand I can withdraw consent at any time.",
"source_agent": "gemini-assistant",
"scope": ["lead_submission"]
},
"vehicle_of_interest": {
"vin": "1HGCY2F57RA000001",
"year": 2024, "make": "Honda", "model": "CR-V", "trim": "EX-L",
"condition": "used",
"stock": "DT-2611",
"body": "suv",
"transmission": "automatic",
"mileage": 14820,
"price": 32995,
"zip": "94107"
},
"trade_in": {
"year": 2020, "make": "Volkswagen", "model": "Passat", "trim": "SE",
"condition": "good",
"mileage": 62000,
"body": "sedan",
"transmission": "automatic"
},
"appointment": {
"appointment_type": "test_drive",
"appointment_at": "2026-05-03T18:00:00Z",
"duration_minutes": 60,
"notes": "I'd like to test the CR-V and have my Passat appraised in the same visit."
},
"message": "I'm interested in the 2024 Honda CR-V EX-L (VIN 1HGCY2F57RA000001). I plan to pay cash and would like to trade in my 2020 Volkswagen Passat with 62,000 miles.",
"source_agent": "gemini-assistant",
"submitted_at": "2026-04-30T11:05:08Z"
}

Response (lead received, appointment confirmed)

{
"type": "lead.submit.response",
"data": {
"lead_id": "lead_2026_04_30_00842",
"status": "received",
"appointment": {
"appointment_id": "appt_2026_04_30_00128",
"status": "confirmed",
"confirmed_at": "2026-05-03T18:00:00Z"
},
"dealer": {
"name": "Demo Toyota",
"phone": "+14155550100"
}
},
"message": "Thanks, Piotr. Test drive confirmed for Sunday May 3 at 11:00 AM Pacific. We've queued your 2020 Passat for an in-person appraisal at the same visit."
}

Variant: customer-only general inquiry (no vehicle, no appointment)

{
"type": "lead.submit.request",
"customer": {
"first_name": "Anna",
"last_name": "Kowalska",
"email": "anna.kowalska@example.com",
"phone": "+14155551234",
"preferred_contact": "email"
},
"consent": {
"granted_at": "2026-04-30T10:42:00Z",
"allowed_channels": ["email"],
"consent_text": "I agree to share my name, email, and phone number with Demo Toyota so a sales representative can answer my financing question by email.",
"source_agent": "chatgpt-shopping-agent",
"scope": ["lead_submission"]
},
"message": "What APR is Demo Toyota offering this month for buyers with 740+ credit?",
"source_agent": "chatgpt-shopping-agent",
"submitted_at": "2026-04-30T10:42:05Z"
}

Variant: appointment with proposed alternatives

When the dealer cannot honor the requested time:

{
"type": "lead.submit.response",
"data": {
"lead_id": "lead_2026_04_30_00843",
"status": "received",
"appointment": {
"appointment_id": "appt_2026_04_30_00129",
"status": "proposed",
"proposed_times": [
"2026-05-03T20:00:00Z",
"2026-05-04T16:00:00Z"
]
},
"dealer": { "name": "Demo Toyota", "phone": "+14155550100" }
},
"message": "We're booked solid Sunday afternoon. The times above are open Sunday evening and Monday afternoon (Pacific). Reply with the time you prefer or call to confirm."
}

The buyer agent SHOULD present the alternatives to the user and re-submit a fresh lead.submit.request with one of the proposed times in appointment.appointment_at.

Why one skill instead of three?

Real shopping flows naturally bundle the inquiry, the trade-in, and the appointment. Forcing buyer agents to make 3 separate calls (with 3 separate consent records) creates:

  • Brittle correlation — dealer CRMs have to re-stitch what was always one customer intent.
  • Consent friction — users sign off 3 disclosures for one decision.
  • Race conditions — the appointment may be booked before the lead arrives, or vice-versa.

A single lead.submit lets the dealer transactionally accept the lead, queue the trade-in for appraisal, and confirm or propose the appointment in one round trip. v0.2 keeps the contract tight by NOT supporting multi-vehicle leads (one vehicle_of_interest per submission); send N requests for N vehicles.

  • consent.allowed_channels[] lists the channels (email, phone, sms) the user authorized for THIS submission.
  • consent.scope[] MUST be ["lead_submission"].
  • The dealer MUST reject the lead with CONTACT_CONSENT_REQUIRED if it intends to follow up via a channel not in allowed_channels.
  • The buyer agent MUST NOT include phone or email without explicit user authorization. See Behavior rules.

Errors

  • CONTACT_CONSENT_REQUIREDconsent missing, scope not ['lead_submission'], or follow-up channel not in allowed_channels.
  • VEHICLE_NOT_FOUND / VEHICLE_UNAVAILABLEvehicle_of_interest reference cannot be located, or no longer available, when a test_drive appointment is requested.
  • APPOINTMENT_TIME_UNAVAILABLE — the requested appointment_at cannot be honored AND the dealer has no proposals to make. The lead may still be received even when the appointment portion fails.
  • INVALID_CONDITIONvehicle_of_interest.condition is in the trade-in vocabulary, or trade_in.condition is in the sale-condition vocabulary.

See Errors for the full vocabulary.

What lead.submit does NOT guarantee

A successful lead.submit.response does not guarantee booking unless data.appointment.status is confirmed. requested and proposed mean the customer has expressed interest but has not been booked. Buyer agents MUST communicate this to the user clearly. See Behavior rules.