Introduction
# Acuity Scheduling
Access the Acuity Scheduling API with managed OAuth authentication. Manage appointments, calendars, clients, availability, and more.
## Quick Start
```bash # List appointments python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/acuity-scheduling/api/v1/appointments?max=10') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
## Base URL
``` https://gateway.maton.ai/acuity-scheduling/{native-api-path} ```
Replace `{native-api-path}` with the actual Acuity API endpoint path. The gateway proxies requests to `acuityscheduling.com` and automatically injects your OAuth token.
## Authentication
All requests require the Maton API key in the Authorization header:
``` Authorization: Bearer $MATON_API_KEY ```
**Environment Variable:** Set your API key as `MATON_API_KEY`:
```bash export MATON_API_KEY="YOUR_API_KEY" ```
### Getting Your API Key
1. Sign in or create an account at [maton.ai](https://maton.ai) 2. Go to [maton.ai/settings](https://maton.ai/settings) 3. Copy your API key
## Connection Management
Manage your Acuity Scheduling OAuth connections at `https://ctrl.maton.ai`.
### List Connections
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=acuity-scheduling&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Create Connection
```bash python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'acuity-scheduling'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Get Connection
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "connection": { "connection_id": "21fd90f9-5935-43cd-b6c8-bde9d915ca80", "status": "ACTIVE", "creation_time": "2025-12-08T07:20:53.488460Z", "last_updated_time": "2026-01-31T20:03:32.593153Z", "url": "https://connect.maton.ai/?session_token=...", "app": "acuity-scheduling", "metadata": {} } } ```
Open the returned `url` in a browser to complete OAuth authorization.
### Delete Connection
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Specifying Connection
If you have multiple Acuity Scheduling connections, specify which one to use with the `Maton-Connection` header:
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/acuity-scheduling/api/v1/appointments') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
If omitted, the gateway uses the default (oldest) active connection.
## API Reference
### Account Information
#### Get Account Info
```bash GET /acuity-scheduling/api/v1/me ```
Returns account information including timezone, scheduling page URL, and plan details.
**Response:** ```json { "id": 12345, "email": "[email protected]", "timezone": "America/Los_Angeles", "name": "My Business", "schedulingPage": "https://app.acuityscheduling.com/schedule.php?owner=12345", "plan": "Professional", "currency": "USD" } ```
### Appointments
#### List Appointments
```bash GET /acuity-scheduling/api/v1/appointments ```
**Query Parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `max` | integer | Maximum results (default: 100) | | `minDate` | date | Appointments on or after this date | | `maxDate` | date | Appointments on or before this date | | `calendarID` | integer | Filter by calendar | | `appointmentTypeID` | integer | Filter by appointment type | | `canceled` | boolean | Include canceled appointments (default: false) | | `firstName` | string | Filter by client first name | | `lastName` | string | Filter by client last name | | `email` | string | Filter by client email | | `excludeForms` | boolean | Omit intake forms for faster response | | `direction` | string | Sort order: ASC or DESC (default: DESC) |
**Example:** ```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/acuity-scheduling/api/v1/appointments?max=10&minDate=2026-02-01') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json [ { "id": 1630290133, "firstName": "Jane", "lastName": "McTest", "phone": "1235550101", "email": "[email protected]", "date": "February 4, 2026", "time": "9:30am", "endTime": "10:20am", "datetime": "2026-02-04T09:30:00-0800", "type": "Consultation", "appointmentTypeID": 88791369, "duration": "50", "calendar": "Chris", "calendarID": 13499175, "canceled": false, "confirmationPage": "https://app.acuityscheduling.com/schedule.php?..." } ] ```
#### Get Appointment
```bash GET /acuity-scheduling/api/v1/appointments/{id} ```
#### Create Appointment
```bash POST /acuity-scheduling/api/v1/appointments Content-Type: application/json
{ "datetime": "2026-02-15T09:00", "appointmentTypeID": 123, "firstName": "John", "lastName": "Doe", "email": "[email protected]", "phone": "555-123-4567", "timezone": "America/New_York" } ```
**Required Fields:** - `datetime` - Date and time (parseable by PHP's strtotime) - `appointmentTypeID` - Appointment type ID - `firstName` - Client's first name - `lastName` - Client's last name - `email` - Client's email
**Optional Fields:** - `phone` - Client phone number - `calendarID` - Specific calendar (auto-selected if omitted) - `timezone` - Client's timezone - `certificate` - Package or coupon code - `notes` - Admin notes - `addonIDs` - Array of addon IDs - `fields` - Array of form field values
**Example:** ```bash python <<'EOF' import urllib.request, os, json data = json.dumps({ 'datetime': '2026-02-15T09:00', 'appointmentTypeID': 123, 'firstName': 'John', 'lastName': 'Doe', 'email': '[email protected]' }).encode() req = urllib.request.Request('https://gateway.maton.ai/acuity-scheduling/api/v1/appointments', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
#### Update Appointment
```bash PUT /acuity-scheduling/api/v1/appointments/{id} Content-Type: application/json
{ "firstName": "Jane", "lastName": "Smith", "email": "[email protected]" } ```
#### Cancel Appointment
```bash PUT /acuity-scheduling/api/v1/appointments/{id}/cancel ```
Returns the canceled appointment with `canceled: true`.
#### Reschedule Appointment
```bash PUT /acuity-scheduling/api/v1/appointments/{id}/reschedule Content-Type: application/json
{ "datetime": "2026-02-20T10:00" } ```
**Note:** The new datetime must be an available time slot.
### Calendars
#### List Calendars
```bash GET /acuity-scheduling/api/v1/calendars ```
**Response:** ```json [ { "id": 13499175, "name": "Chris", "email": "", "replyTo": "[email protected]", "description": "", "location": "", "timezone": "America/Los_Angeles" } ] ```
### Appointment Types
#### List Appointment Types
```bash GET /acuity-scheduling/api/v1/appointment-types ```
**Query Parameters:** - `includeDeleted` (boolean) - Include deleted types
**Response:** ```json [ { "id": 88791369, "name": "Consultation", "active": true, "description": "", "duration": 50, "price": "45.00", "category": "", "color": "#ED7087", "private": false, "type": "service", "calendarIDs": [13499175], "schedulingUrl": "https://app.acuityscheduling.com/schedule.php?..." } ] ```
### Availability
#### Get Available Dates
```bash GET /acuity-scheduling/api/v1/availability/dates?month=2026-02&appointmentTypeID=123 ```
**Required Parameters:** - `month` - Month to check (e.g., "2026-02") - `appointmentTypeID` - Appointment type ID
**Optional Parameters:** - `calendarID` - Specific calendar - `timezone` - Timezone for results (e.g., "America/New_York")
**Response:** ```json [ {"date": "2026-02-09"}, {"date": "2026-02-10"}, {"date": "2026-02-11"} ] ```
#### Get Available Times
```bash GET /acuity-scheduling/api/v1/availability/times?date=2026-02-10&appointmentTypeID=123 ```
**Required Parameters:** - `date` - Date to check - `appointmentTypeID` - Appointment type ID
**Optional Parameters:** - `calendarID` - Specific calendar - `timezone` - Timezone for results
**Response:** ```json [ {"time": "2026-02-10T09:00:00-0800", "slotsAvailable": 1}, {"time": "2026-02-10T09:50:00-0800", "slotsAvailable": 1}, {"time": "2026-02-10T10:40:00-0800", "slotsAvailable": 1} ] ```
### Clients
#### List Clients
```bash GET /acuity-scheduling/api/v1/clients ```
**Query Parameters:** - `search` - Filter by first name, last name, or phone
**Example:** ```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/acuity-scheduling/api/v1/clients?search=John') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json [ { "firstName": "Jane", "lastName": "McTest", "email": "[email protected]", "phone": "(123) 555-0101", "notes": "" } ] ```
#### Create Client
```bash POST /acuity-scheduling/api/v1/clients Content-Type: application/json
{ "firstName": "John", "lastName": "Doe", "email": "[email protected]", "phone": "555-123-4567" } ```
#### Update Client
```bash PUT /acuity-scheduling/api/v1/clients Content-Type: application/json
{ "firstName": "John", "lastName": "Doe", "email": "[email protected]" } ```
**Note:** Client update/delete only works for clients with existing appointments.
#### Delete Client
```bash DELETE /acuity-scheduling/api/v1/clients Content-Type: application/json
{ "firstName": "John", "lastName": "Doe" } ```
### Blocks
#### List Blocks
```bash GET /acuity-scheduling/api/v1/blocks ```
**Query Parameters:** - `max` - Maximum results (default: 100) - `minDate` - Blocks on or after this date - `maxDate` - Blocks on or before this date - `calendarID` - Filter by calendar
#### Get Block
```bash GET /acuity-scheduling/api/v1/blocks/{id} ```
#### Create Block
```bash POST /acuity-scheduling/api/v1/blocks Content-Type: application/json
{ "start": "2026-02-15T12:00", "end": "2026-02-15T13:00", "calendarID": 1234, "notes": "Lunch break" } ```
**Response:** ```json { "id": 9589304654, "calendarID": 13499175, "start": "2026-02-15T12:00:00-0800", "end": "2026-02-15T13:00:00-0800", "notes": "Lunch break", "description": "Sunday, February 15, 2026 12:00pm - 1:00pm" } ```
#### Delete Block
```bash DELETE /acuity-scheduling/api/v1/blocks/{id} ```
Returns 204 No Content on success.
### Forms
#### List Forms
```bash GET /acuity-scheduling/api/v1/forms ```
**Response:** ```json [ { "id": 123, "name": "Client Intake Form", "appointmentTypeIDs": [456, 789], "fields": [ { "id": 1, "name": "How did you hear about us?", "type": "dropdown", "options": ["Google", "Friend", "Social Media"], "required": true } ] } ] ```
### Labels
#### List Labels
```bash GET /acuity-scheduling/api/v1/labels ```
**Response:** ```json [ {"id": 23116714, "name": "Checked In", "color": "green"}, {"id": 23116715, "name": "Completed", "color": "pink"}, {"id": 23116713, "name": "Confirmed", "color": "yellow"} ] ```
## Pagination
Acuity Scheduling uses the `max` parameter to limit results. Use `minDate` and `maxDate` to paginate through date ranges:
```bash # First page GET /acuity-scheduling/api/v1/appointments?max=100&minDate=2026-01-01&maxDate=2026-01-31
# Next page GET /acuity-scheduling/api/v1/appointments?max=100&minDate=2026-02-01&maxDate=2026-02-28 ```
## Code Examples
### JavaScript
```javascript const response = await fetch( 'https://gateway.maton.ai/acuity-scheduling/api/v1/appointments?max=10', { headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}` } } ); const appointments = await response.json(); ```
### Python
```python import os import requests
response = requests.get( 'https://gateway.maton.ai/acuity-scheduling/api/v1/appointments', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}, params={'max': 10} ) appointments = response.json() ```
## Notes
- Datetime values must be parseable by PHP's `strtotime()` function - Timezones use IANA format (e.g., "America/New_York", "America/Los_Angeles") - Client update/delete requires clients to have existing appointments - Rescheduling requires the new datetime to be an available time slot - Use `excludeForms=true` for faster appointment list responses - IMPORTANT: When using curl commands, use `curl -g` when URLs contain brackets to disable glob parsing - IMPORTANT: When piping curl output to `jq` or other commands, environment variables like `$MATON_API_KEY` may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.
## Error Handling
| Status | Meaning | |--------|---------| | 400 | Invalid request (e.g., time not available, client not found) | | 401 | Invalid or missing Maton API key | | 404 | Resource not found | | 429 | Rate limited | | 4xx/5xx | Passthrough error from Acuity API |
### Troubleshooting: API Key Issues
1. Check that the `MATON_API_KEY` environment variable is set:
```bash echo $MATON_API_KEY ```
2. Verify the API key is valid by listing connections:
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Troubleshooting: Invalid App Name
1. Ensure your URL path starts with `acuity-scheduling`. For example:
- Correct: `https://gateway.maton.ai/acuity-scheduling/api/v1/appointments` - Incorrect: `https://gateway.maton.ai/api/v1/appointments`
## Resources
- [Acuity Scheduling API Quick Start](https://developers.acuityscheduling.com/reference/quick-start) - [Appointments API](https://developers.acuityscheduling.com/reference/get-appointments) - [Availability API](https://developers.acuityscheduling.com/reference/get-availability-dates) - [Calendars API](https://developers.acuityscheduling.com/reference/get-calendars) - [Clients API](https://developers.acuityscheduling.com/reference/clients) - [OAuth2 Documentation](https://developers.acuityscheduling.com/docs/oauth2) - [Maton Community](https://discord.com/invite/dBfFAcefs2) - [Maton Support](mailto:[email protected])