What the API does, and when you can skip it
The Acuity Scheduling API is a REST API that lets your own software read and create appointments, check availability and react to bookings. The help center describes it as a way to create, cancel or reschedule appointments from an outside system, or to return intake forms filled in by your own code. In practice, it is the layer you reach for when you are building software on top of Acuity, not when you simply want bookings on your website.
Most businesses never need it. Acuity says so itself: "This API is not needed to integrate Acuity Scheduling with your website, it is intended for developers". Embeds, booking buttons, direct links and Zapier cover most needs without code. A salon that only wants bookings to land in a spreadsheet or a CRM can do that with Zapier on any plan. The API earns its keep when a developer builds a branded booking app, syncs a CRM in depth or runs a nightly report across systems.
Zapier works on any plan and covers most simple automations. Move to the API only when zaps multiply, fail or need logic and full data.
Which plan unlocks what
The plan rule is simple, but it has a twist. API access and custom CSS are available only on Premium, the plan Acuity used to call Powerhouse, while webhooks work on every plan level [1]. Enterprise goes further, with additional APIs and unlimited scheduling instances. Plan for Premium at least. Webhooks only carry IDs, and the full appointment details need an API call. So an integration that reacts to bookings in real time effectively needs Premium, even though the webhooks themselves are available on every plan, Starter included. A Starter account gets the ping, not the booking. If your project depends on reading the booking itself, budget for Premium from day one.
Credentials, authentication and the server rule
Keys and Basic authentication
You find your API credentials in Acuity under Integrations: a numeric user ID and an API key. Enterprise organizations manage keys in their settings instead. The API uses HTTP Basic authentication over SSL, with the user ID as the username and the API key as the password [2]. A failed login returns 401. There are no scoped tokens for a single account. Simple, but blunt.
That bluntness has a cost. Anyone who holds the key can read every client record, so a contractor given the key for a small integration also gets the whole account. Store it in a secrets manager, keep it out of any code repository and rotate it when the work ends. If your app connects many Acuity accounts, such as a marketplace or an agency tool, use OAuth2 instead of collecting keys, so each business authorizes your app on its own. A single business can stay on Basic authentication.
No calls from the browser
Acuity does not support cross-origin requests, because a request sent from the browser would expose the credentials. Every call has to come from your own server or an external one where the key can be stored safely. Plan a small backend. A simple serverless function that holds the key, fetches availability and posts bookings is enough for most custom booking pages, and it keeps the credentials out of the page source.
Docs and SDKs
Developer documentation lives on Acuity's developer site, with an llms.txt index and Markdown versions of each page, plus a separate Enterprise API documentation for the additional APIs. Read the quick start first. There is an official PHP SDK, installed with Composer, and the reference shows JavaScript samples, but any language that can send HTTP requests works. Most teams write thin wrappers. The main resources are appointments, appointment types, calendars, availability, certificates for packages and coupons, payments, webhooks and account metadata.
Acuity blocks browser-side requests because they would expose credentials, and one key unlocks the whole account. Hold it in a small backend and rotate it when a contractor leaves.
Reading bookings and payments
GET /appointments lists bookings, returning up to 100 results by default, with a max parameter to change it. Filters cover date ranges, calendar, appointment type, client name, email, phone and intake field values, so you can build a daily roster, find one client's history or pull every booking that answered yes to a question. A clinic that books 400 appointments a month and pulls them in 100-result pages needs at least four requests for a month of data. Large unfiltered pulls are slow. Combine filters and store the appointment ID for every later call.
By default, canceled appointments are not returned; add canceled or showall to include them. Canceled appointments carry a noShow flag set when the admin has marked the booking as a no-show, which lets you measure no-show rates by service. GET /appointments/:id/payments returns each transaction's ID, date, processor and amount, with Stripe and PayPal as processors and authorize.net and Braintree only for legacy users. Refunds made in the processor are not reflected in Acuity, so reconcile revenue against the processor itself.
Booking through the API without breaking your rules
Availability first, then the booking
The flow runs in three steps: fetch appointment types, then available dates for a month, then times for a date. Times depend on calendars, limits, resources and synced events, so a custom page should ask for times right before showing them and again right before booking. Slots disappear as clients book. POST /appointments creates the booking, and availability and forms are validated as if a client were booking. API bookings send the usual confirmations and run integrations such as calendar sync. When a slot is gone or a form is incomplete, the API returns HTTP 400 with a code such as not_available and a readable message. Show it and fetch new times. Retrying the same slot fails.
Admin mode stays off public pages
Passing admin=true books as an administrator. It switches off availability and attribute validations, allows notes, and requires a valid calendar ID. That suits a front-desk tool that must override limits or add notes for staff, and it is the only way to book around your own rules. On a public page it would let anyone book outside your hours and double-book staff. Keep the two code paths strictly separate.
Add-ons, forms and text consent
Package and coupon codes are validated against the appointment type, and add-ons are passed as IDs and can add time and duration to an appointment before it is booked. Show the client the new price and length. Intake answers go in as field IDs and values, but files cannot be uploaded: a file field takes a string with the file's location, so host it elsewhere and pass a link. If smsOptIn is omitted or false, no text reminder goes out. A custom page that forgets the flag creates bookings that never get a text, which defeats a Standard plan bought partly for texts. For imports and back-office bookings, a noEmail parameter suppresses confirmation emails and texts.
Updates, reschedules and time zones
PUT /appointments/:id updates only a whitelist of fields: names, phone, email, certificate, form fields, notes, labels and SMS opt-in. Anything else is ignored, and required fields such as names cannot be cleared. Rescheduling and canceling use separate endpoints rather than the general update. That keeps the client rules intact: reschedules respect your limits, cancellations send the usual emails, and only admin mode can override them. Mirror your own policy in your app.
Time zones cause most booking bugs. Acuity uses IANA identifiers such as America/New_York, parses new appointments in the business or calendar time zone and handles daylight saving itself. A coaching business that books clients in New York and Los Angeles should store every time with its zone and let Acuity convert, because a three-hour offset applied twice sends clients to the wrong hour. CSV imports can carry a time zone column that overrides the default for that row, and import files are capped at 500 rows. Test a small file first.
Webhooks: events, payloads and the 25 cap
What fires, and how to set it up
Webhooks tell your server when something happens, so you do not have to poll. Acuity sends them when an appointment is scheduled, canceled or rescheduled, and when package, gift certificate or subscription orders complete [3]. Static webhooks are set in the Integrations panel, one URL per event, on port 443 for HTTPS or 80 for HTTP and no longer than 256 characters. Dynamic webhooks are created through the API. One quirk: the reference lists a GET where DELETE is meant, and the example uses DELETE. Trust the example.
Pick only the events you need, since separate URLs per event keep your handler simple, and log every event with its ID. There is also a catch-all changed event that fires on all three actions and whenever details such as an email or a form answer change. Combined with the specific events, it sends duplicates. Use either changed alone or the specific events, and deduplicate by appointment ID either way.
Thin payloads and signatures
Webhook requests are form-encoded POSTs carrying the action, appointment ID, calendar ID and appointment type ID, not the full appointment. Your handler has to call the API for details, which brings Premium back into the picture. A burst of 50 bookings in an hour means 50 follow-up API calls. That is light, but worth queuing so your endpoint answers Acuity quickly. Each webhook carries an x-acuity-signature header, a base64 HMAC-SHA256 of the body using your API key, so reject unsigned or mismatched requests. GET /meta also returns the IP ranges webhooks come from, for allowlisting at your firewall.
Retries, the five-day rule and the cap
Failed calls are retried with exponential backoff over a 24-hour period, but only on HTTP 500 errors or network failures. A webhook that keeps failing for five days is disabled and has to be re-enabled by hand, so a weekend outage can lose events without anyone noticing. Alert on any failed delivery. The hard ceiling is the one most teams meet first: a maximum of 25 webhooks per Acuity account, and Zapier zaps count toward it [4]. Five staff members with five zaps each already reach the cap. Route events through one central endpoint, or one shared Zapier account, and remove zaps nobody uses.
Retries only run for 24 hours, and a webhook that keeps failing for five days is disabled until you re-enable it by hand. Alert on every failed delivery.
Embedding and CSS, no API key needed
Many custom flows need only the embed. The embed code puts the scheduler on any page, and query parameters can prefill or preselect the client's details, the calendar, the appointment type and form fields, including internal-only ones. Calendar IDs come from each calendar's direct link, and the same parameters work in plain links, which makes prefilled links in emails to existing clients easy. The HTML embed also works inside native apps, through WKWebView on iOS and WebView on Android. A studio app can host booking without rebuilding it.
Premium accounts can restyle the scheduling page with CSS, limited to designated selectors so updates do not break customizations. A cleaning company that needed two jobs a day per crew used CSS to hide start times between 9:30 and 11:45, which shows how a few lines can change booking behavior. CSS cannot add features, though, and custom CSS is outside the scope of Acuity's support. If a style breaks after an update, you fix it. Keep styles light.
Limits, security and HIPAA
None of the developer pages we read documents rate limits. That is not the same as having none. A safe pattern is to cache appointment types for an hour, ask for availability only when a client is choosing a time, back off on any error and use webhooks instead of polling. The other gaps are scoped keys, file uploads and, in the pages we read, endpoints for client accounts or package management beyond certificates. Acuity's own enterprise blog admits the API is not fully open, so some companies will hit limitations.
Keep API keys server-side, verify webhook signatures, allowlist webhook IPs and use HTTPS endpoints. HIPAA accounts keep the API, but Zapier is disabled and you are responsible for any third-party system you connect. Moving health data into a non-compliant CRM breaks your compliance, so sign BAAs with every system in the chain and keep the data minimal. At the top end, Enterprise adds additional APIs and an account manager who supports API integrations, webhooks and single sign-on.
Patterns that work, and mistakes to avoid
A CRM sync listens for scheduled, rescheduled and canceled webhooks, fetches each appointment, upserts the client and booking and maps intake answers to CRM fields. Pipedrive's native connection no longer accepts new users, so this pattern replaces it. For a coaching business with 200 bookings a month, that means about 200 webhook calls and 200 detail requests, small enough for a free serverless tier. A custom booking page fetches types and availability, shows your own interface, then posts the booking without admin mode so Acuity validates it. Keep payments on Acuity's page if you can. Nightly reporting pulls appointments by date range, canceled ones included, and joins them with processor payments to calculate no-show rates and revenue per service.
The mistakes repeat, and each shows up in production first:
- Calling the API from the browser.
- Trusting unsigned webhooks.
- Using the changed event and the specific events together.
- Booking in admin mode from a public page.
- Forgetting smsOptIn, or trying to upload files.
- Ignoring the 25-webhook cap.
Test before launch with a test calendar and a private test service. Book with noEmail, run one real $2 payment and refund it, then delete the test clients, which deletes their appointments too. Never test against live client data. When you get stuck, the developer documentation is the main resource; Squarespace support helps with connections, but custom code sits outside its scope. Budget for your own developer time.
Frequently asked questions
Does Acuity Scheduling have an API?+
Yes, a REST API with Basic authentication, OAuth2 for multi-account apps, and webhooks.
Which plan includes the Acuity API?+
Premium (formerly Powerhouse); Enterprise adds further APIs. Webhooks work on every plan.
Can I call the Acuity API from the browser?+
No. Acuity does not support cross-origin requests, so every call has to come from your own or an external server that stores the credentials.
How many webhooks can an Acuity account have?+
A maximum of 25 per account, and Zapier zaps count toward that limit.
Does the Acuity API have rate limits?+
None of the developer pages we read documents them. Cache appointment types briefly, avoid polling and back off on errors.
Can I upload files through the API?+
No. A file intake field takes a string with the file's location, so host the file elsewhere and pass a link.
The bottom line
The Acuity API is simple and practical: Basic authentication, appointment and availability endpoints, signed webhooks with retries and embedding parameters. It needs Premium, lacks documented rate limits and file uploads, and is not fully open. For a typical service business, the right order is native integrations first, then Zapier for small gaps, and only then the API, because each step adds maintenance work a busy owner rarely has time for. If you do build, list the events you need, stand up one HTTPS endpoint that verifies signatures and watch for the five-day disable rule. Our guide to Acuity integrations covers the no-code options, and the Acuity pricing guide shows what Premium costs.
- [1] Acuity Help: Using custom CSS webhooks and APIs (2026-10) https://help.acuityscheduling.com/hc/en-us/articles/16676949253389-Using-custom-CSS-webhooks-and-APIs
- [2] Acuity developer docs: reference quick start (2026-10) https://developers.acuityscheduling.com/reference/quick-start.md
- [3] Acuity developer docs: docs webhooks (2026-10) https://developers.acuityscheduling.com/docs/webhooks.md
- [4] Acuity developer docs: page webhooks webhooks webhooks (2026-10) https://developers.acuityscheduling.com/page/webhooks-webhooks-webhooks.md