Skip to main content

Appointment Object

Appointment webhook events deliver a data.appointment payload describing the current state of the appointment record at the time the event was emitted. The same appointment object shape is used for all appointment event types — the event type in the hopdrive-event header tells you what changed, and the body tells you the full current state.

For the event envelope wrapping the payload, see the event object. For the list of appointment event types, see webhook events.

Fields

FieldTypeDescription
idintegerThe HopDrive appointment ID.
statusstringThe internal HopDrive status of the appointment. One of new, pending, ready, paying, paid, canceled, refunded, failed.
external_idstring | nullThe external scheduler's appointment identifier (e.g. SLT appointment number for Spark-sourced appointments). Forms a unique key together with source.
sourcestringThe system that originally created this appointment (e.g. spark, api, dealer-portal). Useful for subscriber-side filtering and loop prevention — see below.
source_statusstring | nullThe external scheduler's own status string, kept alongside HopDrive's internal status and never overwritten by it. Provided for visibility only; changes to source_status alone do not produce outbound webhooks.
transport_typestring | nullThe elected transportation type. One of waiter, valet, mobile_service, shuttle, rideshare, or null if no transportation type has been selected yet.
consumer_vehicle_directionstring | nullThe direction the consumer's vehicle is travelling for this appointment. Currently always to_dealer for inbound scheduler-sourced appointments.
appointment_timestring | nullISO-8601 timestamp for when the service appointment is scheduled.
consumer_namestring | nullThe consumer's full name.
consumer_phonestring | nullThe consumer's phone number. Preferred cellular number when supplied by the source system.
consumer_emailstring | nullThe consumer's email address.
vehicle_makestring | nullVehicle make.
vehicle_modelstring | nullVehicle model.
vehicle_yearinteger | nullVehicle model year.
vehicle_colorstring | nullVehicle color.
vehicle_vinstring | nullVehicle VIN.
vehicle_trimstring | nullVehicle trim.
ro_numberstring | nullRepair order number. Often absent on initial creation because most dealers do not create the RO until the vehicle physically arrives at the dealership for service. Once an RO is acquired it is preserved — a subsequent update from the source system that lacks an RO will not null it out.
loaner_requestedboolean | nullWhether a loaner vehicle was requested with this appointment.
move_idinteger | nullThe HopDrive move ID created from this appointment, or null if no move has been created yet. When this transitions from null to a value, an appointment.move.created event is emitted. Use GET /v1/moves/:id to fetch full move details.
customer_idintegerThe HopDrive customer (rooftop) ID this appointment belongs to.
driver_notesstring | nullFree-form notes intended for the driver.
updatedatstringISO-8601 timestamp of the most recent update to the appointment row.
updatedbystringIdentifier of the actor that performed the most recent update. Examples: spark-webhook (change came from an inbound Spark webhook), a dealer email address (change came from the dealer portal), event-handler (change came from an internal HopDrive event handler). Useful for subscriber-side loop prevention — see below.

Loop prevention with source and updatedby

Outbound appointment webhooks fire on every meaningful lifecycle event regardless of who wrote the row. The publisher does not filter by source — that responsibility lives with each subscriber. Use the two fields together as follows:

  • source tells you who originally created the appointment. A scheduler integration may want to ignore events for appointments that did not originate in its own system.
  • updatedby tells you who made the specific change being delivered. A scheduler integration must ignore events that it itself caused, otherwise an inbound webhook from the scheduler would trigger an outbound webhook back to the scheduler in a loop.

For example, a Spark integration that forwards HopDrive appointment changes back into Spark should check data.appointment.updatedby and discard the event (returning 200) whenever the value is spark-webhook, because that change originated from Spark in the first place.

Event type vs. payload

The event type in the hopdrive-event header indicates exactly what changed (e.g. appointment_canceled, appointment_upgraded, appointment_rescheduled). The payload is always the full current state of the appointment — there is no changed_columns field and no diff. If you need to know the previous value of a field, persist it on your side from the prior delivery.

Example Payload

POST {your_target_url}
host: webhook.site
content-length: 1024
hopdrive-event: appointment_upgraded
user-agent: HopDrive-Webhooks/1.0.0
HopDrive-Signature: t=1763051200000,v1=8b9a40e7c5e4f15d2c1a08f9d3e6b7c4a2918f60d5e7c2b1a3e6f9d8c7b5a4f3
content-type: application/json
accept: application/json, text/plain

{
"id": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
"object": "event",
"version": "1.0.0",
"data": {
"appointment": {
"id": 48217,
"status": "ready",
"external_id": "SLT-9938712",
"source": "spark",
"source_status": "Pending",
"transport_type": "valet",
"consumer_vehicle_direction": "to_dealer",
"appointment_time": "2026-05-20T14:30:00+00:00",
"consumer_name": "Jordan Rivera",
"consumer_phone": "+15555550143",
"consumer_email": "jordan.rivera@example.com",
"vehicle_make": "Toyota",
"vehicle_model": "Camry",
"vehicle_year": 2023,
"vehicle_color": "Silver",
"vehicle_vin": "4T1B11HK7KU123456",
"vehicle_trim": "XSE",
"ro_number": null,
"loaner_requested": false,
"move_id": null,
"customer_id": 59,
"driver_notes": "Gate code 4421. Park in driveway.",
"updatedat": "2026-05-13T17:42:11.882034+00:00",
"updatedby": "service-advisor@example-dealer.com"
}
}
}