> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sparkserv.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Book an appointment

> Discover services and scheduling choices, find a time, and submit a booking.

Start with the [quickstart](https://docs.sparkserv.com/quickstart.md) environment variables. Obtain a token with `dealerships:read scheduling:read appointments:create` as described in [Authentication](https://docs.sparkserv.com/authentication.md). These examples use cURL and jq in the same shell.

> [!WARNING]
>
> The API origin in these examples is production. The final request creates a real appointment. Use approved customer data and dealership access, and do not submit the synthetic example customer.

## 1. Discover departments

```bash theme={null}
curl --fail-with-body --silent --show-error \
  "$SPARK_API_URL/public/v1/departments" \
  --header "Authorization: Bearer $SPARK_ACCESS_TOKEN" \
  --header "Dealership-Id: $DEALERSHIP_ID"
```

The response includes `items` and a `selectionMode`: `selectable`, `configured`, or `not-exposed`. Do not assume every scheduler exposes a department picker. When a department is selectable, use an ID from `items`. Otherwise, omit `departmentId` and use the configured scheduling context. If the API requires a selection, inspect the error's `code` and `details`.

## 2. Discover services for the vehicle

Create a shared request context. The customer below is synthetic; replace it with the customer's approved details. Supply a VIN, or supply `year`, `make`, and `model`. Include trim and mileage when needed.

```bash theme={null}
export DEPARTMENT_ID=''

CONTEXT=$(jq -n --arg departmentId "$DEPARTMENT_ID" '{
  customer: {
    firstName: "Alex", lastName: "Example",
    phoneNumber: "2025550100", email: "alex@example.com"
  },
  vehicle: {year: 2024, make: "Honda", model: "Civic", mileage: 15000}
} + (if $departmentId == "" then {} else {departmentId: $departmentId} end)')

curl --fail-with-body --silent --show-error \
  "$SPARK_API_URL/public/v1/services/search" \
  --header "Authorization: Bearer $SPARK_ACCESS_TOKEN" \
  --header "Dealership-Id: $DEALERSHIP_ID" \
  --header 'Content-Type: application/json' \
  --data "$CONTEXT"
```

Set `DEPARTMENT_ID` to your selected department ID **before** building `CONTEXT`, or leave it empty when you omit the selection. Customer identity is required during discovery only when the scheduler needs it; this recipe supplies it consistently.

The response includes the resolved `vehicle`, `department`, `timezone`, and service `items`. Choose a service ID from `items`. Prices and available durations are estimates, not a guaranteed quote.

Check `commentsAllowed`, `commentsRequired`, and `commentsDefault` for your service. Supply service comments at booking if required and no suitable default exists.

## 3. Discover advisors and transport

Choose a future date in the dealership's timezone. `startDate` and `endDate` are inclusive local dates, with at most seven dates in one discovery request. This example uses one date; `startDate` defaults to today when omitted.

```bash theme={null}
export SERVICE_ID='service-uuid-from-your-response'
export START_DATE='YYYY-MM-DD'

OPTIONS=$(jq --arg serviceId "$SERVICE_ID" --arg date "$START_DATE" \
  '. + {serviceIds: [$serviceId], startDate: $date, endDate: $date}' \
  <<< "$CONTEXT")

curl --fail-with-body --silent --show-error \
  "$SPARK_API_URL/public/v1/advisors/search" \
  --header "Authorization: Bearer $SPARK_ACCESS_TOKEN" \
  --header "Dealership-Id: $DEALERSHIP_ID" \
  --header 'Content-Type: application/json' \
  --data "$OPTIONS"

curl --fail-with-body --silent --show-error \
  "$SPARK_API_URL/public/v1/transports/search" \
  --header "Authorization: Bearer $SPARK_ACCESS_TOKEN" \
  --header "Dealership-Id: $DEALERSHIP_ID" \
  --header 'Content-Type: application/json' \
  --data "$OPTIONS"
```

Use IDs from the returned `items`, not display names. The advisor choice `any` represents Any Advisor. Omitting `advisorId` in availability means any eligible advisor; omitting `transportId` selects a safe drop-off default.

## 4. Find an available time

```bash theme={null}
export ADVISOR_ID='advisor-id-from-your-response'
export TRANSPORT_ID='transport-id-from-your-response'

AVAILABILITY_REQUEST=$(jq \
  --arg advisorId "$ADVISOR_ID" --arg transportId "$TRANSPORT_ID" \
  '. + {advisorId: $advisorId, transportId: $transportId}' <<< "$OPTIONS")

curl --fail-with-body --silent --show-error \
  "$SPARK_API_URL/public/v1/availability/search" \
  --header "Authorization: Bearer $SPARK_ACCESS_TOKEN" \
  --header "Dealership-Id: $DEALERSHIP_ID" \
  --header 'Content-Type: application/json' \
  --data "$AVAILABILITY_REQUEST"
```

Choose a slot from `items`. `appointmentAt` is a UTC instant; `appointmentAtLocal` includes the dealership-local offset. Preserve the selected instant, the slot's `advisorId`, and the response's `transport.id` for booking. Do not strip the timezone offset.

If no slots are returned, try another valid date or scheduling selection. If you change the vehicle, department, services, advisor, or transport, repeat the relevant discovery before booking.

> [!NOTE]
>
> Availability is an observation, not a hold. A slot can become unavailable before you book it.

## 5. Submit the booking

Set these values from the availability response. Do not substitute a made-up appointment time.

```bash theme={null}
export APPOINTMENT_AT='appointmentAt-from-your-selected-slot'
export SLOT_ADVISOR_ID='advisorId-from-your-selected-slot'
export RESOLVED_TRANSPORT_ID='transport-id-from-availability-response'

BOOKING_REQUEST=$(jq \
  --arg serviceId "$SERVICE_ID" --arg appointmentAt "$APPOINTMENT_AT" \
  --arg advisorId "$SLOT_ADVISOR_ID" \
  --arg transportId "$RESOLVED_TRANSPORT_ID" \
  '. + {services: [{id: $serviceId}], appointmentAt: $appointmentAt,
    advisorId: $advisorId, transportId: $transportId}' <<< "$CONTEXT")
```

This payload uses service defaults for comments. If your chosen service requires customer input, add `comments` to its entry in `services` before submitting. Omitted or `null` service comments use the default; an empty string clears optional comments. Appointment-level `comments` are a separate field.

Review the payload and confirm the customer, vehicle, services, and time before executing:

```bash theme={null}
curl --fail-with-body --silent --show-error \
  "$SPARK_API_URL/public/v1/appointments" \
  --header "Authorization: Bearer $SPARK_ACCESS_TOKEN" \
  --header "Dealership-Id: $DEALERSHIP_ID" \
  --header 'Content-Type: application/json' \
  --data "$BOOKING_REQUEST"
```

A successful request returns `201` with appointment details. See the [booking reference](https://docs.sparkserv.com/api-reference/appointments/book-an-appointment.md) for the full schema. Save the returned `id` for [reading, updating, or canceling](https://docs.sparkserv.com/guides/manage-appointments.md).

If the selected slot is no longer available, refresh availability and ask the customer to choose again. For a timeout or `BOOKING_OUTCOME_UNKNOWN`, **do not blindly submit again**. Follow [Errors and safe retries](https://docs.sparkserv.com/guides/errors-and-retries.md).

## Optional: look up a saved customer

`POST /public/v1/customers/search` accepts a complete phone number, email address, or VIN in `search` and requires `customers:read` plus `Dealership-Id`. It searches authorized Spark records only; it does not query or import scheduler records.

Results contain customer IDs and saved vehicle IDs. Booking also accepts `customerId` and `vehicleId`; use the [booking reference](https://docs.sparkserv.com/api-reference/appointments/book-an-appointment.md) for those fields. This guide uses inline details instead. Do not assume arbitrary combinations of saved IDs and inline details are interchangeable.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.