The Zenbooker API provides a logical path to build a complete, end-to-end booking experience within your own application. The process follows a sequence of steps: first, you identify the correct territory for a customer; next, you define the job's scope and duration; then, you find an available time slot; and finally, you create the booking.
This guide walks you through the entire flow with practical examples and code snippets.
Prerequisites
All API requests require an Authorization header with your bearer token:
Authorization: Bearer <YOUR_API_KEY>
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. A territory represents a branch, team of providers, or geographic zone. This identification is essential 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", // 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
}
}
}
}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.
Option A: Using your Zenbooker service catalog
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:
{
"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
}
]
}
]
}
]
}Duration calculation
Calculate total duration by summing:
- Service
base_duration - Each selected option's
duration
Example: Base service (120 min) + Large TV option (15 min) = 135 minutes total
Option B: Custom services
Choose this for simpler integrations where you define service details dynamically. This approach works well for:
- Custom service builders: When you've built your own service configuration flow and just need to pass the final price and duration
- Dynamic pricing models: Services where you calculate price/duration based on external factors Simple bookings: "Book a 1-hour appointment" without options
With this approach:
- No API call needed in this step
- Simply determine your duration (e.g., 60 minutes)
- Set arbitrary service details (name, duration, price) later when creating the job
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
territory: Territory ID from Step 1 (required)date: Start date in YYYY-MM-DD format (required)duration: Job duration in minutes (required)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
}'Service configuration options
Catalog Service
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"
}
]
}
]
}Custom Service
How you can define custom services for a job with arbitrary price, name, and description.
{
"custom_service": {
"name": "Emergency repair consultation",
"description": "Initial assessment and quote",
"price": 75.00,
"duration": 45,
"taxable": true
}
}Additional options
Enhance bookings with optional parameters:
assignment_method:"auto"or"offer"for provider assignmentsms_notifications: Enable SMS updates for customersemail_notifications: Enable email updatesjob_number: Custom job reference number
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
Error handling
- Always check
in_service_areabefore proceeding - Handle timezone conversions properly
Performance optimization
- Cache service catalog data when appropriate
- Include customer coordinates for accurate scheduling
- Batch timeslot requests for multiple days by setting the
daysparameter.
Your booking flow is complete! The customer is scheduled, and you can display confirmation details with the job ID for future reference.