Skip to main content
RapidDev - Software Development Agency
lovable-integrationsEdge Function Integration

How to Integrate Lovable with Acuity Scheduling

Connect Acuity Scheduling to Lovable by creating an Edge Function that calls Acuity's REST API using your User ID and API key stored in Cloud Secrets. Build custom booking widgets, availability calendars, and appointment management dashboards. Acuity offers deeper customization than Calendly — intake forms, payment collection, and appointment packages — making it ideal for service businesses with complex booking needs.

What you'll learn

  • How to find your Acuity Scheduling User ID and API key
  • How to build an Edge Function that queries Acuity availability and creates appointments
  • How to embed a custom booking calendar in a Lovable app
  • How to handle Acuity webhooks for booking confirmation and cancellation notifications
  • When to choose Acuity versus Calendly for your booking use case
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read30 minutesSchedulingMarch 2026RapidDev Engineering Team
TL;DR

Connect Acuity Scheduling to Lovable by creating an Edge Function that calls Acuity's REST API using your User ID and API key stored in Cloud Secrets. Build custom booking widgets, availability calendars, and appointment management dashboards. Acuity offers deeper customization than Calendly — intake forms, payment collection, and appointment packages — making it ideal for service businesses with complex booking needs.

Build Custom Booking Experiences with Acuity Scheduling in Lovable

Acuity Scheduling is designed for service businesses that need more than a simple meeting link — consultants, coaches, salons, medical practices, fitness studios, and anyone who collects intake information, processes payments at booking, or manages multiple service types with different durations and pricing. While Acuity's self-hosted booking page is customizable, embedding it in a Lovable app with a fully matched brand and custom booking flow creates a much more polished experience.

The Acuity REST API gives you full control over the booking lifecycle. You can query available time slots for specific appointment types and date ranges, create appointments with client intake form data, cancel or reschedule appointments, and retrieve appointment history. Acuity also supports webhooks that send real-time notifications to your Lovable app when appointments are booked, cancelled, or rescheduled.

The primary advantage of Acuity over Calendly for this integration is the intake form system. Acuity lets you define custom questions that clients answer at booking — health information for medical providers, project details for consultants, preferences for service providers. This intake data is returned by the API and can be stored in your Lovable app's Supabase database alongside the appointment for richer client management.

Integration method

Edge Function Integration

Acuity Scheduling connects to Lovable through an Edge Function that calls Acuity's REST API with HTTP Basic Auth using your User ID and API key stored in Cloud Secrets. The Edge Function handles appointment types, availability, booking creation, and appointment management.

Prerequisites

  • A Lovable account with a project open and Lovable Cloud enabled
  • An active Acuity Scheduling account with at least one appointment type configured
  • Your Acuity User ID and API key from Acuity's Integrations settings
  • At least one appointment type ID (visible in the appointment type URL when editing it in Acuity)
  • Understanding of your Acuity intake form structure if you want to display or collect form responses

Step-by-step guide

1

Get Your Acuity User ID and API Key

Log in to your Acuity Scheduling account and navigate to Business Settings (click the gear icon or your business name in the top-right). Look for 'Integrations' in the left sidebar and click on 'API'. You'll see your User ID (a numeric identifier) and the option to generate or view your API key. If no API key exists, click 'Generate API Key'. Copy both the User ID and the API key immediately — save them somewhere safe before leaving the page. Acuity's API key is shown only once in some configurations. Acuity's API uses HTTP Basic Authentication where the User ID is the username and the API key is the password. The API base URL is https://acuityscheduling.com/api/v1. The authentication header is constructed by Base64-encoding 'userId:apiKey' and sending it as 'Authorization: Basic {base64}'. Also note your appointment type IDs. Navigate to Business Settings → Appointment Types, click on an appointment type, and look at the URL — it contains the appointment type ID (e.g., .../appointment-types/12345). You'll need this ID when querying availability for a specific session type.

Pro tip: Acuity provides a sandbox test mode for API development. In your Acuity developer settings, you can enable test mode which creates test appointments that don't appear on your real calendar. Use this during development to test booking flows without cluttering your production calendar.

Expected result: You have your Acuity User ID (a number like 12345678) and API key. You know at least one appointment type ID for testing the availability endpoint.

2

Store Acuity Credentials in Cloud Secrets

In Lovable, click the '+' button next to the Preview panel to open the Cloud tab, then navigate to Secrets. Add these secrets: - ACUITY_USER_ID: your Acuity numeric User ID - ACUITY_API_KEY: your Acuity API key The Edge Function constructs the Basic Auth header by Base64-encoding 'userId:apiKey' using btoa(). This is straightforward — no special encoding or token exchange is needed. Acuity's API key provides full access to your Acuity account including all client data, appointments, and business settings. Protect it carefully. Never paste it in the Lovable chat panel or include it in any client-side code. Lovable's security system actively blocks hardcoded credentials, but the Cloud Secrets panel is the safe and correct storage location.

Pro tip: If you're building for a client who uses Acuity, have them generate a separate API key specifically for your Lovable integration. This makes it easy to revoke access if the engagement ends without affecting other integrations they may have.

Expected result: ACUITY_USER_ID and ACUITY_API_KEY are stored in Cloud Secrets. The Edge Function can construct the Basic Auth header and call the Acuity API.

3

Create the Acuity Scheduling Edge Function

Create the Edge Function that proxies Acuity API calls. The Acuity API is well-documented at developers.acuityscheduling.com and follows standard REST conventions with clean JSON responses. Key Acuity endpoints for a booking integration: GET /availability/dates to find available booking dates for an appointment type and month, GET /availability/times to find available time slots for a specific date and appointment type, POST /appointments to create a new appointment, GET /appointments to list appointments (with optional email, date range, and appointment type filters), GET /appointments/{id} for appointment details, and DELETE /appointments/{id} to cancel. The availability endpoints require appointmentTypeID as a query parameter and return arrays of dates (for /dates) or time slot objects with datetime and slotsAvailable fields (for /times). The appointment creation endpoint requires firstName, lastName, email, datetime, and appointmentTypeID at minimum, plus any form fields your appointment type requires. Build the Edge Function to handle all these operations from a single function to keep the Cloud Functions list clean.

Lovable Prompt

Create an Edge Function called acuity-proxy at supabase/functions/acuity-proxy/index.ts. Read ACUITY_USER_ID and ACUITY_API_KEY from Deno environment variables and authenticate with Basic Auth (btoa of userId:apiKey). Accept POST requests with: operation (string: getAvailableDates, getAvailableTimes, createAppointment, getAppointments, getAppointment, cancelAppointment), and operation-specific params (for getAvailableDates: appointmentTypeID, month (YYYY-MM); for getAvailableTimes: appointmentTypeID, date (YYYY-MM-DD); for createAppointment: appointmentTypeID, datetime, firstName, lastName, email, phone, fields (array for intake form); for getAppointments: email, minDate, maxDate, appointmentTypeID; for cancelAppointment: id). Call the appropriate Acuity API endpoint. Include CORS headers and error handling.

Paste this in Lovable chat

supabase/functions/acuity-proxy/index.ts
1// supabase/functions/acuity-proxy/index.ts
2import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
3
4const corsHeaders = {
5 "Access-Control-Allow-Origin": "*",
6 "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
7 "Access-Control-Allow-Methods": "POST, OPTIONS",
8};
9
10const ACUITY_BASE = "https://acuityscheduling.com/api/v1";
11
12serve(async (req: Request) => {
13 if (req.method === "OPTIONS") {
14 return new Response("ok", { headers: corsHeaders });
15 }
16
17 try {
18 const userId = Deno.env.get("ACUITY_USER_ID");
19 const apiKey = Deno.env.get("ACUITY_API_KEY");
20 const authHeader = `Basic ${btoa(`${userId}:${apiKey}`)}`;
21
22 const { operation, ...params } = await req.json();
23 let url = ACUITY_BASE;
24 let method = "GET";
25 let body: string | undefined;
26
27 switch (operation) {
28 case "getAvailableDates":
29 url += `/availability/dates?appointmentTypeID=${params.appointmentTypeID}&month=${params.month}&timezone=America/New_York`;
30 break;
31 case "getAvailableTimes":
32 url += `/availability/times?appointmentTypeID=${params.appointmentTypeID}&date=${params.date}&timezone=America/New_York`;
33 break;
34 case "createAppointment":
35 url += "/appointments";
36 method = "POST";
37 body = JSON.stringify(params);
38 break;
39 case "getAppointments":
40 url += "/appointments?" + new URLSearchParams(Object.fromEntries(Object.entries(params).filter(([,v]) => v))).toString();
41 break;
42 case "getAppointment":
43 url += `/appointments/${params.id}`;
44 break;
45 case "cancelAppointment":
46 url += `/appointments/${params.id}`;
47 method = "DELETE";
48 break;
49 default:
50 return new Response(JSON.stringify({ error: "Unknown operation" }), { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } });
51 }
52
53 const response = await fetch(url, {
54 method,
55 headers: { "Authorization": authHeader, "Content-Type": "application/json" },
56 ...(body ? { body } : {}),
57 });
58 const data = await response.json();
59 return new Response(JSON.stringify(data), { status: response.status, headers: { ...corsHeaders, "Content-Type": "application/json" } });
60 } catch (error) {
61 return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } });
62 }
63});

Pro tip: The timezone parameter in availability requests is important. Pass the user's browser timezone to Acuity (JavaScript's Intl.DateTimeFormat().resolvedOptions().timeZone) so available times display in the user's local timezone, not a hardcoded one.

Expected result: The acuity-proxy Edge Function is deployed. Testing the getAvailableDates operation with a valid appointment type ID returns an array of available date strings.

4

Build the Multi-Step Booking Flow

With the Edge Function working, open Lovable chat and describe the booking flow UI. A good booking experience uses a step-by-step approach that reduces cognitive load — show one decision at a time rather than all booking fields at once. A standard 3-step booking flow: Step 1 — Calendar showing available dates (green dots on available days, grayed out on unavailable). User clicks a date to proceed. Step 2 — Time slot grid showing available appointment times for the selected date. User clicks a time to proceed. Step 3 — Client information form with name, email, phone, and any intake questions. User clicks 'Book' to create the appointment. For the calendar in Step 1, Acuity returns an array of available date strings. Build a monthly calendar component that marks available dates and disables unavailable ones. Include navigation for the current and next 2 months. For the time slots in Step 2, Acuity returns objects with time and slotsAvailable. Display times in the client's local timezone. Group times by morning/afternoon/evening if there are many slots. For the confirmation in Step 3, after a successful appointment creation, display the confirmed date, time, appointment type, and a calendar add link. Send the booking details to the client's email (Acuity handles this automatically if email confirmations are enabled in your Acuity settings).

Lovable Prompt

Using the acuity-proxy Edge Function, build a 3-step booking flow for appointment type ID 12345. Step 1: a monthly calendar component where available dates (from getAvailableDates for the current and next month) show as clickable green circles and unavailable dates are gray. Step 2: after selecting a date, show a grid of available time slots (from getAvailableTimes) formatted in the user's local timezone. Step 3: a form with First Name, Last Name, Email, Phone (required), and a 'Message or questions' text area (optional). On submit, call createAppointment and show a success card with the confirmed appointment details. Include a progress indicator showing the current step.

Paste this in Lovable chat

Pro tip: Handle the timezone carefully. Use JavaScript's Intl.DateTimeFormat().resolvedOptions().timeZone to detect the user's timezone and pass it to Acuity's availability endpoints. Display confirmed appointment times using the same timezone so the confirmed time matches what the user selected.

Expected result: A 3-step booking flow works end to end. Selecting a date shows available times, completing the form creates an Acuity appointment, and the confirmation appears with the booked date and time. The appointment appears in Acuity's calendar interface.

5

Set Up Acuity Webhooks for Real-Time Notifications

After the booking flow is working, add Acuity webhook support to enable real-time notifications when appointments are booked, rescheduled, or cancelled. This is valuable for triggering downstream workflows — sending a welcome email, creating a Supabase record, notifying a Slack channel, or updating a CRM. Create a Lovable Edge Function as the webhook receiver. In your Acuity account under Business Settings → Integrations → Webhooks, add the Edge Function URL and select the events you want to receive: booking.scheduled, booking.rescheduled, booking.canceled. Acuity sends a POST request to your webhook URL with appointment data in the body. The webhook body includes the appointment ID, type, client name, email, date, time, and form fields. Your Edge Function should acknowledge receipt with a 200 response quickly, then process the event asynchronously. Acuity does not sign webhooks with an HMAC signature like Stripe does, so you cannot cryptographically verify the origin. Add a secret query parameter to your webhook URL (e.g., ?secret=your_webhook_secret) and verify it in the Edge Function to prevent unauthorized calls.

Lovable Prompt

Create a webhook receiver Edge Function called acuity-webhook at supabase/functions/acuity-webhook/index.ts. It should: verify a secret query parameter (ACUITY_WEBHOOK_SECRET from Deno.env.get) to authenticate the webhook, accept POST requests with Acuity appointment data (action: booking.scheduled/rescheduled/canceled, appointmentID, datetime, appointmentTypeID, firstName, lastName, email, forms), save the appointment event to a Supabase table called booking_events (with columns: event_id, action, appointment_id, appointment_type, client_name, client_email, booked_at, appointment_datetime), and return 200 OK immediately. Then configure my Acuity webhook URL to: {my-supabase-url}/functions/v1/acuity-webhook?secret={ACUITY_WEBHOOK_SECRET}.

Paste this in Lovable chat

Expected result: Booking an appointment in Acuity (via your Lovable booking flow or directly) triggers a webhook that creates a record in the booking_events Supabase table. Check Cloud → Logs to see webhook receipt confirmation.

Common use cases

Build a custom booking widget for a service business website

A coaching or consulting business wants a booking widget embedded in their Lovable-built website that matches their brand exactly — not Acuity's generic booking page. The widget shows available times for their session type, collects intake information through a custom form, and creates the Acuity appointment on submission.

Lovable Prompt

I run a coaching practice and use Acuity Scheduling. I want a booking widget on my Lovable website. I've stored ACUITY_USER_ID and ACUITY_API_KEY in Cloud Secrets. My Acuity appointment type ID is 12345 (60-minute strategy session). Create an Edge Function called acuity-proxy that: gets available dates for the next 30 days for appointment type 12345, gets available times for a selected date, and creates an appointment with client name/email/phone plus intake form answers. Then build a 3-step booking flow: (1) calendar showing available dates, (2) time slot selector for the chosen date, (3) intake form with name, email, goals, experience level fields, and a 'Book Session' button.

Copy this prompt to try it in Lovable

Create a client portal showing appointment history and upcoming sessions

Existing clients log in to a Lovable portal to see their upcoming appointments, past session history, and a rebooking shortcut. The portal queries Acuity for appointments filtered by the client's email address.

Lovable Prompt

I want a client portal showing users their Acuity appointments. Using ACUITY_USER_ID and ACUITY_API_KEY from Cloud Secrets, create an Edge Function that fetches appointments filtered by email address — GET /appointments?email={email}. Appointments have: id, datetime, endTime, appointmentTypeID, type, firstName, lastName, email, phone, notes, forms (intake answers array), canceled (boolean), paid (string). Build a portal page showing upcoming appointments (future, not canceled) as cards with session type, date/time, and a cancel button, plus a list of past sessions with date and any notes.

Copy this prompt to try it in Lovable

Build an admin dashboard for managing Acuity appointments

A service business owner wants a custom dashboard showing all upcoming appointments across all appointment types, with the ability to view client intake forms, mark no-shows, and see daily/weekly booking volume metrics.

Lovable Prompt

Build an admin booking dashboard for my Acuity account. Using ACUITY_USER_ID and ACUITY_API_KEY, create Edge Functions that: list all upcoming appointments for the next 7 days (GET /appointments?minDate=today&maxDate=7days), list all appointment types (GET /appointment-types), and get appointment details with intake form answers (GET /appointments/{id}). Build a dashboard with: a weekly calendar view showing appointments by day, a sidebar with today's appointments and client names, a detail panel opening when an appointment is clicked showing all intake form answers, and KPI cards showing bookings this week vs last week.

Copy this prompt to try it in Lovable

Troubleshooting

Acuity API returns 401 Unauthorized with 'Invalid credentials'

Cause: The User ID or API key is incorrect, or the User ID is not being treated as a string — Acuity User IDs are numeric but must be passed as strings in the Basic Auth header.

Solution: Verify ACUITY_USER_ID and ACUITY_API_KEY in Cloud Secrets. Ensure the Basic Auth encoding uses the numeric User ID as a string: btoa('12345678:your-api-key'). Regenerate the API key in Acuity Business Settings → Integrations → API if you suspect the current key is invalid.

getAvailableDates returns an empty array even though dates are available in Acuity

Cause: The appointmentTypeID is incorrect, the month format is wrong, or the calendar has no availability configured in Acuity for the requested month.

Solution: Verify the appointment type ID from the Acuity URL when editing the appointment type. The month parameter must be formatted as YYYY-MM (e.g., 2026-03). Also check in your Acuity calendar settings that availability hours are configured for the requested month — if no working hours are set, all dates return as unavailable.

Appointment creation returns 'The time you selected is no longer available'

Cause: The selected time slot was taken between when the user viewed available times and when they submitted the booking form.

Solution: This is a race condition inherent to any booking system. Handle it gracefully: catch the error in the booking form submission, clear the selected time, reload available times for the selected date, and show a message: 'That time was just booked — please select another time.' Implement an optimistic booking UI that moves to the confirmation screen quickly and handles this error with a clear recovery path.

Available times display in the wrong timezone (e.g., showing EST times to PST users)

Cause: The timezone parameter passed to Acuity's availability endpoint is not matching the user's local timezone.

Solution: Detect the user's browser timezone using Intl.DateTimeFormat().resolvedOptions().timeZone and pass it as the timezone parameter in both getAvailableDates and getAvailableTimes calls. Display the confirmed time using new Date(datetime).toLocaleString() with the user's timezone rather than a hardcoded format.

typescript
1// Get user timezone in React component
2const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
3// Pass to Edge Function call
4await fetch('/functions/v1/acuity-proxy', {
5 method: 'POST',
6 body: JSON.stringify({ operation: 'getAvailableTimes', appointmentTypeID: 12345, date: selectedDate, timezone: userTimezone })
7});

Best practices

  • Pass the user's browser timezone to all Acuity availability requests using Intl.DateTimeFormat().resolvedOptions().timeZone to ensure times display correctly across time zones
  • Handle the 'time no longer available' race condition gracefully by reloading availability and prompting time reselection rather than showing a generic error
  • Use Acuity's webhook system to trigger downstream workflows rather than polling for new bookings — webhooks are immediate while polling adds latency
  • Store the Acuity appointment ID in your Supabase database when creating appointments so you can query or cancel them later without requiring the client's email
  • Limit the availability calendar to 3 months ahead — fetching availability too far in advance may be inaccurate if the service provider's schedule changes
  • Add a clear 'View on Acuity' link in your admin dashboard for appointment records so administrators can access Acuity's full interface for complex actions
  • Configure Acuity's built-in email confirmation and reminder emails rather than building them in Lovable — Acuity handles timezone-correct, customizable confirmations natively
  • Test the complete booking flow including cancellation before launch — confirm that cancellations update both the Acuity calendar and any Supabase records you maintain

Alternatives

Frequently asked questions

Can I accept payments through the Acuity booking flow in my Lovable app?

Acuity's built-in payment processing (via Stripe or PayPal, configured in your Acuity account) is tied to Acuity's own booking page. When creating appointments through the API, you bypass Acuity's payment collection. To accept payments in your custom Lovable booking flow, integrate Stripe separately in Lovable and process the payment before or after calling Acuity's appointment creation API. Alternatively, redirect users to Acuity's payment confirmation page after API booking.

How do I embed Acuity's booking page in Lovable if I don't want to build a custom booking UI?

You can embed Acuity's scheduling iframe directly in a Lovable React component. Ask Lovable to create a component that renders Acuity's embed code: <iframe src='https://app.acuityscheduling.com/schedule.php?owner={userId}' width='100%' height='800px' frameBorder='0' />. This requires no Edge Function and uses Acuity's fully featured booking UI within your app. The downside is limited customization — you cannot fully match your brand or collect additional custom data.

Does the Acuity API support multiple calendars or locations?

Yes, Acuity supports multiple calendars (one per staff member or location) in the API. Each calendar has a calendarID, and you can filter availability and appointment queries by calendarID. Pass the calendarID parameter in your availability requests to show slots for a specific staff member or location. This is useful for service businesses with multiple practitioners where clients choose a specific person.

How do I handle Acuity's intake form fields in the booking creation API call?

Acuity intake form fields are passed as a forms array in the appointment creation request. Each form has a fieldID and a value. Get the field IDs by calling GET /appointment-types/{id} which returns the form structure with field IDs. Store these IDs as constants in your Edge Function code. Then when creating appointments, pass the intake data as: fields: [{ id: 12345, value: 'user answer' }]. Get the IDs from your Acuity API response, not by guessing.

Can I set up recurring appointments through the Acuity API?

Acuity's API supports creating individual appointments, not recurring series in a single call. To implement recurring booking in your Lovable app, create multiple individual appointments using your own scheduling logic — for example, creating the same appointment time for each of the next 8 weeks using a loop in your Edge Function. Acuity treats each appointment as independent, so cancelling one does not affect the others in the series.

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.