Build a custom booking flow

Learn how to build a complete end-to-end booking experience using the Zenbooker API. This guide walks through the four-step process: territory identification, job definition, timeslot selection, and booking creation.

Prerequisites

All API requests require an Authorization header with your bearer token:

Authorization: Bearer <YOUR_API_KEY>

Overview of the booking process

Step 1: Territory Check

Identify the service territory responsible for the customer's location

Step 2: Define Job

Determine the job scope and calculate total duration in minutes

Step 3: Find Timeslots

Query available times for the territory

Step 4: Create Booking

Submit the complete job with all gathered information


Step 1: Identify the service territory

The first and most critical step is determining if you can service a customer's location, and if so, which specific service territory is responsible for it. This identification is needed because all subsequent steps—availability checking, scheduling, and staff assignment—are territory-specific.

Every booking starts with location validation. This step determines:

  • Whether you service the area
  • Which territory (branch/team) handles it

Use the service_area_check endpoint for location lookup and routing:

curl -G "https://api.zenbooker.com/v1/scheduling/service_area_check" \
  --data-urlencode "postal_code=20901" \
  -H "Authorization: Bearer <YOUR_API_KEY>"
Understanding the Response
{
  "in_service_area": true,
  "service_territory": {
    "id": "1586239489452x571449227260704600", // Store this for getting timeslots and booking later
    "name": "Silver Spring Team",             // Territory name
    "timezone": "America/New_York"
  },
  "customer_location": {
    "coordinates": {  // Store this to pass to the timeslots endpoint later (optional)
      "lat": 39.0191,
      "lng": -77.0076    
    }
  }
}

Key fields to store:

  • service_territory.id - Required for timeslots and booking
  • customer_location.coordinates - Optional but improves scheduling accuracy

💡 Why territories matter

Territories are geographic boundaries that represent distinct operational units with their own schedules, providers, and rules. The same time might be available in one territory but not another.


Step 2: Define the job and duration

Once you know which territory handles the work, define what the work entails. The goal is determining the job's total duration in minutes, required for finding available time slots.

For customers choosing from existing services and add-ons, first fetch your list of services:

curl "https://api.zenbooker.com/v1/services?is_visible=true" \
  -H "Authorization: Bearer <YOUR_API_KEY>"

The response includes detailed service information with base duration and configurable options that can add additional time.

Duration Calculation: Calculate total duration by summing the service base_duration plus each selected option's duration.

Example: Base service (120 min) + Large TV option (15 min) = 135 minutes total

Service Response Structure
{
  "results": [
    {
      "service_id": "1760300167598x745029266608947700",
      "name": "Home Theater TV Mounting & Setup",
      "base_duration": 120,
      "base_price": "149.00",
      "sections": [
        {
          "section_id": "1760300168129x855444251360474400",
          "section_type": "price_modifier",
          "title": "TV size (select one)",
          "input_type": "radio_buttons",
          "options": [
            {
              "option_id": "1760300168599x299965067990447740",
              "name": "Up to 49-inch TV",
              "price": "0.00",
              "duration": 0
            },
            {
              "option_id": "1760300168685x597574803337188900",
              "name": "50–65-inch TV",
              "price": "30.00",
              "duration": 15
            }
          ]
        }
      ]
    }
  ]
}

Step 3: Find available timeslots

Query the schedule for your identified territory using the duration from Step 2:

curl -G "https://api.zenbooker.com/v1/scheduling/timeslots" \
  --data-urlencode "territory=1586239489452x571449227260704600" \
  --data-urlencode "date=2025-10-28" \
  --data-urlencode "duration=135" \
  --data-urlencode "lat=39.0191" \
  --data-urlencode "lng=-77.0076" \
  -H "Authorization: Bearer <YOUR_API_KEY>"
Key Parameters

Required Parameters:

  • territory - Territory ID from Step 1
  • date - Start date in YYYY-MM-DD format
  • duration - Job duration in minutes

Optional Parameters:

  • days - Number of days to return (default: 7)
  • lat/lng - Customer coordinates for accurate scheduling
Response Structure
{
  "territory_id": "1586239489452x571449227260704600",
  "timezone": "America/New_York",
  "days": [
    {
      "date": "2025-10-28",
      "timeslots": [
        {
          "start": "2025-10-28T13:00:00.000Z",
          "end": "2025-10-28T17:00:00.000Z",
          "type": "arrival_window",
          "formatted": "9:00 AM - 1:00 PM",
          "id": "slot_1761051600_1761066000"
        }
      ]
    }
  ]
}

Present these options to customers and capture the selected timeslot id.


Step 4: Create the job

With all necessary information gathered, create the job with a single POST request. The services parameter accepts both catalog services and custom services.

curl -X POST "https://api.zenbooker.com/v1/jobs" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "territory_id": "1586239489452x571449227260704600",
    "timeslot_id": "slot_1761051600_1761066000",
    "customer": {
      "name": "Jane Doe",
      "email": "[email protected]",
      "phone": "555-123-4567"
    },
    "address": {
      "line1": "123 Main St",
      "city": "Silver Spring",
      "state": "MD",
      "postal_code": "20901"
    },
    "services": [
      {
        "service_id": "1760300167598x745029266608947700",
        "selections": [
          {
            "section_id": "1760300168129x855444251360474400",
            "selected_options": [{
              "option_id": "1760300168685x597574803337188900"
            }]
          }
        ]
      },
      {
        "custom_service": {
          "name": "Haul away old TV",
          "price": 50.00,
          "duration": 15,
          "taxable": false
        }
      }
    ],
    "sms_notifications": true,
    "email_notifications": true
  }'

How you represent a customer booking an existing service with selected options:

{
  "service_id": "1760300167598x745029266608947700",
  "selections": [
    {
      "section_id": "1760300168129x855444251360474400",
      "selected_options": [
        {
          "option_id": "1760300168685x597574803337188900",
          "quantity": 1,
          "comments": "Handle with care"
        }
      ]
    }
  ]
}
Additional Options

Assignment Methods:

  • assignment_method: "auto" or "offer" for provider assignment

Notifications:

  • sms_notifications: Enable SMS updates for the customer
  • email_notifications: Enable email updates for the customer
Success Response

A successful 201 Created response confirms the booking:

{
  "job_id": "1761023232848x682214498988670500",
  "status": "scheduled",
  "customer_id": "1759877773365x180935398640097200",
  "timeslot": {
    "type": "arrival_window",
    "start": "2025-10-28T13:00:00.000Z",
    "end": "2025-10-28T17:00:00.000Z"
  },
  "pricing": {
    "subtotal": "199.00",
    "tax_amount": "15.92",
    "total": "214.92"
  }
}

Best practices

  • Cache service catalog data when appropriate
  • Include customer coordinates when requesting timeslots if your scheduling settings include things like distance or drive time limits between jobs.
  • Request timeslots for multiple days in one request by setting the days parameter.

Your booking flow is complete! The customer is scheduled, and you can display confirmation details with the job ID for future reference.