Skip to main content
RapidDev - Software Development Agency
bolt-ai-integrationsBolt Chat + API Route

How to Integrate Bolt.new with Zocdoc

Zocdoc does not offer a public developer API for external app integration. To add healthcare appointment booking to a Bolt.new app, embed the Zocdoc booking widget if you are a verified healthcare provider, link to provider Zocdoc profiles from a directory-style app, or build a fully custom appointment booking system using Supabase with doctor profiles, availability slots, and booking management. The custom approach gives you full control.

What you'll learn

  • Why Zocdoc has no public API and what integration options actually exist for developers
  • How to embed the Zocdoc booking widget in a Bolt.new app as a verified healthcare provider
  • How to build a full custom appointment booking system with doctor profiles and time slots using Supabase
  • How to display availability grids and handle booking confirmations with email notifications
  • How to deploy your Bolt healthcare app and set up webhook-based appointment reminders
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read45 minutesOtherApril 2026RapidDev Engineering Team
TL;DR

Zocdoc does not offer a public developer API for external app integration. To add healthcare appointment booking to a Bolt.new app, embed the Zocdoc booking widget if you are a verified healthcare provider, link to provider Zocdoc profiles from a directory-style app, or build a fully custom appointment booking system using Supabase with doctor profiles, availability slots, and booking management. The custom approach gives you full control.

Integrating Healthcare Appointment Booking with Bolt.new

Zocdoc is one of the most-searched healthcare integrations for Bolt.new, but there is an important reality to understand upfront: Zocdoc does not provide a public REST API for independent developers. Unlike Stripe, Twilio, or Supabase — which publish open developer docs and offer API keys to anyone — Zocdoc's booking infrastructure is a closed platform. API access is only available to healthcare organizations and enterprise partners through a formal agreement process. If you are a solo developer or building an independent app, you cannot call Zocdoc's backend directly.

This does not mean you are stuck. There are three real paths forward. First, if you are a verified Zocdoc healthcare provider, Zocdoc offers embeddable booking widgets that can be placed in your own website — this is the official, supported integration method for practices already on Zocdoc. Second, you can build a healthcare directory app in Bolt that links to individual Zocdoc provider profile pages, letting Zocdoc handle the actual booking flow while your app handles discovery and filtering. Third — and most powerful for founders building a product — you can build a fully custom appointment booking system directly in Bolt using Supabase as the backend. This approach gives you complete control: you own the data, the UX, and the booking logic, without being constrained by Zocdoc's platform rules.

For most Bolt.new developers building a healthcare startup or internal clinic tool, the custom Supabase approach is the right answer. You can build doctor profiles, specialty filtering, real-time availability grids, booking confirmation emails via SendGrid, and appointment reminder workflows — everything Zocdoc provides, but tailored to your specific use case. This tutorial covers all three paths so you can choose the one that fits your situation, with the most detailed walkthrough focused on the custom booking system.

Integration method

Bolt Chat + API Route

Zocdoc has no public API for external developers — access requires a formal partnership agreement that is only available to healthcare providers and enterprise clients. The practical integration paths for Bolt.new developers are: embedding Zocdoc's booking widget (for verified providers), deep-linking to Zocdoc provider profiles from a healthcare directory app, or building a custom appointment booking system in Bolt using Supabase as the backend. The custom Supabase approach is the most powerful and gives you full control over the booking flow.

Prerequisites

  • A Bolt.new project (Vite or Next.js — both work for this integration)
  • A Supabase account at supabase.com for building the custom booking backend (free tier is sufficient)
  • A Zocdoc provider account if you want to embed the official Zocdoc booking widget (only available to verified healthcare practices)
  • Basic understanding of Supabase tables and row-level security policies
  • Optional: a SendGrid or Resend API key for sending appointment confirmation emails

Step-by-step guide

1

Understand Your Integration Path Before Building

Before writing a single line of code, decide which of the three integration paths fits your use case. This decision saves significant time. Path 1 — Zocdoc Widget Embed: if you are a verified Zocdoc healthcare provider (a clinic, practice, or individual physician already listed on Zocdoc), log in to your Zocdoc provider portal and look for 'Website Integration' or 'Booking Widget' options. Zocdoc provides embeddable HTML snippets that add their booking interface to your site. This is the only officially supported way to use Zocdoc's booking system outside of zocdoc.com. You cannot access this without an active Zocdoc provider account — there is no self-serve widget for general developers. Path 2 — Link to Zocdoc Profiles: if you are building a healthcare directory or navigation product, you can build the discovery and filtering UI in Bolt while linking to individual Zocdoc profile URLs. Zocdoc profile pages follow a predictable URL pattern (zocdoc.com/doctor/name-NNN). Your Supabase database stores provider details and their Zocdoc profile URL; clicking 'Book' in your app opens that URL in a new tab. This approach requires no API and no partnership agreement. Path 3 — Custom Booking System: if you are building a product for a specific clinic, telehealth startup, or healthcare SaaS, build the entire booking flow from scratch in Bolt with Supabase as the backend. You own the data, control the UX, and have no dependency on Zocdoc's platform or policies. This tutorial focuses on Path 3 as it applies to the widest range of developers and gives the most capability.

Pro tip: Zocdoc's API partnership program is designed for health systems and large practices — not individual developers. If you email Zocdoc's developer contact requesting API access, expect no response or a referral to their enterprise sales team. Build the custom system instead.

Expected result: You have clarity on which integration path matches your use case and are ready to proceed with the appropriate implementation.

2

Design the Supabase Schema for Appointment Booking

A robust appointment booking system needs at minimum three Supabase tables: doctors, availability_slots, and appointments. The doctors table stores provider information — name, specialty, bio, photo URL, and any filtering metadata like accepted insurance or languages spoken. The availability_slots table represents individual bookable time windows — each slot belongs to a doctor, has a start and end time, and an is_booked boolean flag. When a patient books, you update the slot's is_booked field to true and create a record in the appointments table. The appointments table links to the booked slot and stores patient contact information. This normalized structure prevents double-booking: the is_booked flag on the slot is the single source of truth for availability. For real-world applications, also add a Supabase Row Level Security policy so patients can only read their own appointment records and doctors can only read their own schedules. In the Bolt prompt, describe the full schema so the AI generates matching TypeScript types and Supabase queries. Adding a status field to appointments (pending, confirmed, cancelled, completed) enables a full appointment lifecycle workflow. Time zones are a common source of bugs — store all times in UTC in Supabase and convert to the user's local timezone in the frontend using the browser's Intl.DateTimeFormat API.

Bolt.new Prompt

Set up Supabase for a clinic appointment booking system. Create these tables: doctors (id uuid primary key, name text, specialty text, bio text, photo_url text, is_active boolean default true, created_at timestamptz default now()), availability_slots (id uuid primary key, doctor_id uuid references doctors(id), start_time timestamptz, end_time timestamptz, is_booked boolean default false, created_at timestamptz default now()), appointments (id uuid primary key, slot_id uuid references availability_slots(id), patient_name text, patient_email text, patient_phone text, notes text, status text default 'confirmed', created_at timestamptz default now()). Create TypeScript types for all three tables. Set up the Supabase client in lib/supabase.ts using VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY.

Paste this in Bolt.new chat

lib/supabase.ts
1// lib/supabase.ts
2import { createClient } from '@supabase/supabase-js';
3
4export type Doctor = {
5 id: string;
6 name: string;
7 specialty: string;
8 bio: string;
9 photo_url: string;
10 is_active: boolean;
11 created_at: string;
12};
13
14export type AvailabilitySlot = {
15 id: string;
16 doctor_id: string;
17 start_time: string;
18 end_time: string;
19 is_booked: boolean;
20 created_at: string;
21};
22
23export type Appointment = {
24 id: string;
25 slot_id: string;
26 patient_name: string;
27 patient_email: string;
28 patient_phone: string;
29 notes: string;
30 status: 'confirmed' | 'cancelled' | 'completed';
31 created_at: string;
32};
33
34const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
35const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
36
37export const supabase = createClient(supabaseUrl, supabaseKey);

Pro tip: Store all datetimes as UTC in Supabase. Display them in the patient's local timezone on the frontend using new Date(slot.start_time).toLocaleString('en-US', { timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone }). This prevents confusion for telehealth apps where doctor and patient may be in different time zones.

Expected result: Supabase tables are created and the TypeScript types match the schema. The Supabase client is initialized and ready to query.

3

Build the Doctor Directory and Availability Calendar

The patient-facing booking flow starts with a doctor selection screen. Fetch the active doctors list from Supabase and display them in a filterable grid — specialty, location, and insurance are the most common filter dimensions for healthcare apps. When a patient clicks a doctor, show their profile and a calendar-style availability grid. The availability grid is the most complex UI element: query the availability_slots table for this doctor filtered to is_booked = false and start_time > now(), then group slots by date to render a week or month view. Each available slot appears as a clickable button. Use a date-picker library or build a simple grid that displays the next 7-14 days with time slots organized by hour. Selecting a slot moves the patient to the booking form step. Implement optimistic UI updates — when a patient clicks a slot, immediately show it as selected in the UI while the booking form loads. This prevents the jarring experience of a slot appearing available but being grabbed by another patient between click and form submission. For the actual booking, use a Supabase transaction or RLS policy to handle the race condition: the Supabase update query with a where clause on is_booked = false acts as an optimistic lock — if two patients try to book the same slot simultaneously, only the first one whose UPDATE query executes against is_booked = false will succeed.

Bolt.new Prompt

Build the patient-facing appointment booking UI. Step 1: A DoctorList page that fetches active doctors from Supabase and displays them in a grid with photo, name, specialty, and 'View Availability' button. Add a specialty filter dropdown. Step 2: A DoctorProfile page with availability calendar. Fetch availability_slots where doctor_id matches, is_booked is false, and start_time is in the future. Group slots by date and display them as a calendar. Clicking a slot opens the booking form. Step 3: A BookingForm component with fields for patient name, email, phone, and optional notes. On submit, update the slot's is_booked to true and insert an appointment record. Show a success confirmation with the appointment details.

Paste this in Bolt.new chat

hooks/useAvailability.ts
1// hooks/useAvailability.ts
2import { useState, useEffect } from 'react';
3import { supabase, AvailabilitySlot } from '@/lib/supabase';
4
5export function useAvailability(doctorId: string) {
6 const [slots, setSlots] = useState<AvailabilitySlot[]>([]);
7 const [loading, setLoading] = useState(true);
8
9 useEffect(() => {
10 if (!doctorId) return;
11 const fetchSlots = async () => {
12 const now = new Date().toISOString();
13 const { data, error } = await supabase
14 .from('availability_slots')
15 .select('*')
16 .eq('doctor_id', doctorId)
17 .eq('is_booked', false)
18 .gte('start_time', now)
19 .order('start_time', { ascending: true });
20 if (!error && data) setSlots(data);
21 setLoading(false);
22 };
23 fetchSlots();
24 }, [doctorId]);
25
26 return { slots, loading };
27}
28
29export async function bookAppointment(
30 slotId: string,
31 patient: { name: string; email: string; phone: string; notes: string }
32) {
33 // Mark slot as booked
34 const { error: slotError } = await supabase
35 .from('availability_slots')
36 .update({ is_booked: true })
37 .eq('id', slotId)
38 .eq('is_booked', false); // Optimistic lock — fails if already booked
39
40 if (slotError) throw new Error('This slot was just booked by someone else. Please choose another time.');
41
42 // Create appointment record
43 const { data, error: apptError } = await supabase
44 .from('appointments')
45 .insert({
46 slot_id: slotId,
47 patient_name: patient.name,
48 patient_email: patient.email,
49 patient_phone: patient.phone,
50 notes: patient.notes,
51 status: 'confirmed',
52 })
53 .select()
54 .single();
55
56 if (apptError) throw apptError;
57 return data;
58}

Pro tip: The .eq('is_booked', false) condition in the UPDATE query acts as a race condition guard. If two patients submit the booking form for the same slot at the same millisecond, only the first UPDATE that finds is_booked = false will succeed. Show a friendly error for the second patient.

Expected result: Patients can browse doctors, see available time slots in a calendar view, and complete the booking form. Duplicate bookings are prevented by the optimistic lock pattern.

4

Add Confirmation Emails and Deploy

After a successful booking, send a confirmation email to both the patient and the doctor. In Bolt's WebContainer development environment, outbound HTTP calls to email APIs work fine — you can call the Resend or SendGrid API directly from the frontend or via an API route during development. However, during development in Bolt's WebContainer, incoming webhooks cannot reach the browser-based runtime. This matters if you want to set up automated appointment reminders via a scheduled webhook service — those reminders need to fire against your deployed URL, not the Bolt preview. For reminder automation, deploy your app first and then configure the reminder service with your deployed Netlify or Vercel URL. The confirmation email should include the appointment date and time (formatted in the patient's time zone), the doctor's name and specialty, a cancellation link, and the clinic's address or a video meeting link for telehealth. Use Resend for sending emails since it offers a generous free tier and a simple REST API. Store your RESEND_API_KEY in the .env file for development and in Netlify's environment variables for production. When deploying to Netlify via Bolt's Settings → Applications, the Bolt WebContainer's node_modules are rebuilt in Netlify's standard Node.js environment — all packages work normally after deployment.

Bolt.new Prompt

Add confirmation email sending after a successful booking. Create app/api/send-confirmation/route.ts (Next.js) that accepts POST with appointment details and sends two emails using the Resend API: one to the patient with their appointment summary (doctor name, date/time, clinic address) and one to the doctor with the patient's name and contact info. Store RESEND_API_KEY in .env. Call this API route from the booking success handler on the frontend.

Paste this in Bolt.new chat

app/api/send-confirmation/route.ts
1// app/api/send-confirmation/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4export async function POST(request: NextRequest) {
5 const { appointment, slot, doctor, patientEmail, doctorEmail } = await request.json();
6
7 const formattedTime = new Date(slot.start_time).toLocaleString('en-US', {
8 weekday: 'long',
9 year: 'numeric',
10 month: 'long',
11 day: 'numeric',
12 hour: '2-digit',
13 minute: '2-digit',
14 timeZoneName: 'short',
15 });
16
17 const resendApiKey = process.env.RESEND_API_KEY;
18
19 // Email to patient
20 await fetch('https://api.resend.com/emails', {
21 method: 'POST',
22 headers: {
23 'Authorization': `Bearer ${resendApiKey}`,
24 'Content-Type': 'application/json',
25 },
26 body: JSON.stringify({
27 from: 'appointments@yourclinic.com',
28 to: patientEmail,
29 subject: `Appointment Confirmed: ${doctor.name} on ${formattedTime}`,
30 html: `<h2>Your appointment is confirmed!</h2>
31 <p><strong>Doctor:</strong> ${doctor.name} (${doctor.specialty})</p>
32 <p><strong>Date & Time:</strong> ${formattedTime}</p>
33 <p><strong>Patient:</strong> ${appointment.patient_name}</p>
34 <p>Reply to this email if you need to reschedule.</p>`,
35 }),
36 });
37
38 // Email to doctor
39 await fetch('https://api.resend.com/emails', {
40 method: 'POST',
41 headers: {
42 'Authorization': `Bearer ${resendApiKey}`,
43 'Content-Type': 'application/json',
44 },
45 body: JSON.stringify({
46 from: 'appointments@yourclinic.com',
47 to: doctorEmail,
48 subject: `New Appointment: ${appointment.patient_name} at ${formattedTime}`,
49 html: `<h2>New appointment booked</h2>
50 <p><strong>Patient:</strong> ${appointment.patient_name}</p>
51 <p><strong>Contact:</strong> ${appointment.patient_email} / ${appointment.patient_phone}</p>
52 <p><strong>Time:</strong> ${formattedTime}</p>
53 <p><strong>Notes:</strong> ${appointment.notes || 'None'}</p>`,
54 }),
55 });
56
57 return NextResponse.json({ success: true });
58}

Pro tip: During development in Bolt's WebContainer, outbound calls to Resend's API work fine. But if you want appointment reminder webhooks (e.g., triggered by a cron service 24 hours before the appointment), those must be registered with your deployed Netlify URL — incoming webhooks cannot reach the Bolt WebContainer during development.

Expected result: After a successful booking, the patient and doctor both receive confirmation emails with the appointment details. The email API route works in both development and production.

Common use cases

Healthcare Provider Directory with Booking Links

Build a searchable directory of healthcare providers that filters by specialty, insurance, location, and availability. Each provider card links to their Zocdoc booking page, letting Zocdoc handle appointment scheduling while your app handles discovery. Ideal for aggregator apps or healthcare navigation tools.

Bolt.new Prompt

Build a healthcare provider directory app. Each doctor has a name, specialty, location, accepted insurance list, average rating, and a bookingUrl (external Zocdoc link). Display providers in a searchable, filterable grid with cards showing their photo, name, specialty, and a 'Book Appointment' button that opens bookingUrl in a new tab. Add filters for specialty and insurance. Use Supabase to store the provider data.

Copy this prompt to try it in Bolt.new

Custom Clinic Appointment Booking System

Build a white-label appointment booking system for a single clinic or medical practice, replacing Zocdoc with a fully custom solution. Patients select a doctor, choose an available time slot, enter their details, and receive a confirmation email. The clinic admin panel shows all upcoming appointments.

Bolt.new Prompt

Build a clinic appointment booking system using Supabase. Create three tables: doctors (id, name, specialty, bio, photo_url), availability_slots (id, doctor_id, start_time, end_time, is_booked), and appointments (id, slot_id, patient_name, patient_email, patient_phone, notes, created_at). Build a patient-facing booking flow: step 1 select doctor, step 2 pick available slot from a calendar grid, step 3 enter contact details, step 4 confirmation page. Build an admin view showing all upcoming appointments grouped by doctor.

Copy this prompt to try it in Bolt.new

Telehealth Scheduling App with Video Link

Build a telehealth appointment booking app where patients schedule video consultations. After booking, both the doctor and patient receive a confirmation email with a Zoom or Google Meet video link. The doctor's dashboard shows upcoming appointments with join links.

Bolt.new Prompt

Build a telehealth scheduling app. Doctors can set their weekly availability (recurring time blocks by day of week and hour). Patients book available slots. After booking, send confirmation emails using the Resend API to both doctor and patient with the appointment details and a video meeting link (store the meeting_url in the appointment record). Show the doctor's upcoming appointments in a dashboard sorted by date. Use Supabase for all data storage and React Hook Form for the booking form.

Copy this prompt to try it in Bolt.new

Troubleshooting

Double-bookings occur — two patients book the same time slot

Cause: The booking logic does not use an atomic check-and-update. If two patients submit the form simultaneously, both read is_booked = false, both proceed, and both create appointment records.

Solution: Use the optimistic lock pattern: in the UPDATE query, add .eq('is_booked', false) to the WHERE clause. The first update succeeds and sets is_booked = true. The second update finds no rows matching is_booked = false and returns 0 rows updated — check rowCount and throw an error if 0.

typescript
1const { data, error, count } = await supabase
2 .from('availability_slots')
3 .update({ is_booked: true })
4 .eq('id', slotId)
5 .eq('is_booked', false) // Atomic lock
6 .select();
7
8if (!data || data.length === 0) {
9 throw new Error('This slot was just taken. Please choose another time.');
10}

Available slots do not update in real time — a slot another patient booked still appears as available

Cause: The availability query is a one-time fetch that runs when the component mounts. It does not re-fetch when other patients book slots.

Solution: Use Supabase's real-time subscription to listen for changes on the availability_slots table. Subscribe to UPDATE events filtered by doctor_id, and remove newly booked slots from the local state when is_booked changes to true.

typescript
1useEffect(() => {
2 const channel = supabase
3 .channel('slots-changes')
4 .on('postgres_changes', {
5 event: 'UPDATE',
6 schema: 'public',
7 table: 'availability_slots',
8 filter: `doctor_id=eq.${doctorId}`,
9 }, (payload) => {
10 if (payload.new.is_booked) {
11 setSlots(prev => prev.filter(s => s.id !== payload.new.id));
12 }
13 })
14 .subscribe();
15 return () => supabase.removeChannel(channel);
16}, [doctorId]);

Confirmation email API route works in Bolt's preview but fails after Netlify deployment

Cause: The RESEND_API_KEY environment variable is set in the .env file locally but was not added to Netlify's environment variables before deployment.

Solution: In Netlify's dashboard, go to Site Configuration → Environment Variables and add RESEND_API_KEY with your production key. Trigger a redeploy so Netlify picks up the new environment variable. The .env file is not deployed to Netlify — environment variables must be set in the hosting dashboard.

Appointment reminder webhooks work locally but not in production — reminders are never sent

Cause: The reminder webhook URL was configured with the Bolt WebContainer preview URL, which is ephemeral and not publicly accessible. Incoming webhooks cannot reach Bolt's browser-based runtime during development.

Solution: Register your Netlify or Vercel deployed URL as the webhook target in your reminder service (e.g., a cron service like EasyCron or a Supabase scheduled function). The URL should be your production domain, not the Bolt preview URL.

Best practices

  • Store all appointment times as UTC timestamps in Supabase and convert to the user's local timezone on the frontend — never store timezone-aware strings
  • Use the optimistic lock pattern (.eq('is_booked', false) in the UPDATE WHERE clause) to prevent double-bookings in high-traffic situations
  • Add Supabase Row Level Security policies so patients can only read their own appointment records, not the entire appointments table
  • Enable Supabase real-time on the availability_slots table so the booking calendar auto-removes slots as they are booked by other users
  • Deploy your app before registering any webhook URLs for appointment reminders — incoming webhooks cannot reach Bolt's WebContainer during development
  • Include a cancellation link in confirmation emails so patients can cancel without calling the clinic — store a unique cancellation token in the appointments table
  • Build a simple admin dashboard for clinic staff to view, confirm, and cancel appointments — do not expose the Supabase service role key to the frontend

Alternatives

Frequently asked questions

Does Zocdoc have a public API for developers?

No. Zocdoc does not offer a public REST API or developer program for independent developers. API access is only available through a formal partnership agreement with Zocdoc, which is limited to healthcare organizations and enterprise clients. If you contact Zocdoc's developer team as an individual developer, you will be referred to their enterprise sales team.

Can I embed a Zocdoc booking widget in my Bolt.new app?

Only if you are a verified Zocdoc healthcare provider. Zocdoc offers embeddable booking widgets for practices already listed on their platform. Log in to your Zocdoc provider portal and look for website integration options. If you are not already a Zocdoc-listed provider, this path is not available to you.

What is the best way to add healthcare appointment booking to a Bolt.new app without Zocdoc's API?

Build a custom appointment booking system using Supabase as the backend. Create tables for doctors, availability_slots, and appointments in Supabase, then use Bolt's AI to generate the booking UI and logic. This approach gives you full control over the patient experience, data ownership, and booking rules. Pair with Resend or SendGrid for confirmation emails.

Can I build an appointment booking system in Bolt that works like Zocdoc?

Yes. A Bolt.new app with Supabase can replicate all of Zocdoc's core functionality: doctor profiles with specialties and bios, real-time availability calendars, multi-step booking forms, confirmation emails, and an admin dashboard for managing appointments. The main difference is that you manage the platform yourself rather than relying on Zocdoc's patient acquisition network.

Do appointment reminder webhooks work during development in Bolt?

No. Incoming webhooks from external services cannot reach Bolt's WebContainer during development — the browser-based runtime has no public URL. Outbound API calls (including sending confirmation emails) work fine in the preview. For webhook-based appointment reminders, deploy your app to Netlify or Vercel first, then register your deployed URL as the webhook target.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.