🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Acuity Scheduling

by @byungkyu

Acuity Scheduling API integration with managed OAuth. Manage appointments, calendars, clients, and availability. Use this skill when users want to schedule,...

Versionv1.0.3
Downloads5,880
Installs5
Stars⭐ 3
TERMINAL
clawhub install acuity-scheduling

πŸ“– About This Skill


name: acuity-scheduling description: | Acuity Scheduling API integration with managed OAuth. Manage appointments, calendars, clients, and availability. Use this skill when users want to schedule, reschedule, or cancel appointments, check availability, or manage clients and calendars. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). compatibility: Requires network access and valid Maton API key metadata: author: maton version: "1.0" clawdbot: emoji: 🧠 requires: env: - MATON_API_KEY

Acuity Scheduling

Access the Acuity Scheduling API with managed OAuth authentication. Manage appointments, calendars, clients, availability, and more.

Quick Start

# List appointments
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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://api.maton.ai/acuity-scheduling/{native-api-path}

Maton 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:

export MATON_API_KEY="YOUR_API_KEY"

Getting Your API Key

1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key

Connection Management

Manage your Acuity Scheduling OAuth connections at https://api.maton.ai.

List Connections

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'acuity-scheduling'}).encode()
req = urllib.request.Request('https://api.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

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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:

{
  "connection": {
    "connection_id": "{connection_id}",
    "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

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/acuity-scheduling/api/v1/appointments')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If you have multiple connections, always include this header to ensure requests go to the intended account.

Security & Permissions

  • Access is scoped to appointments, calendars, clients, and availability within the connected Acuity Scheduling account.
  • All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
  • API Reference

    Account Information

    #### Get Account Info

    GET /acuity-scheduling/api/v1/me
    

    Returns account information including timezone, scheduling page URL, and plan details.

    Response:

    {
      "id": 12345,
      "email": "user@example.com",
      "timezone": "America/Los_Angeles",
      "name": "My Business",
      "schedulingPage": "https://app.acuityscheduling.com/schedule.php?owner=12345",
      "plan": "Professional",
      "currency": "USD"
    }
    

    Appointments

    #### List Appointments

    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:

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.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:

    [
      {
        "id": 1630290133,
        "firstName": "Jane",
        "lastName": "McTest",
        "phone": "1235550101",
        "email": "jane.mctest@example.com",
        "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

    GET /acuity-scheduling/api/v1/appointments/{id}
    

    #### Create Appointment

    POST /acuity-scheduling/api/v1/appointments
    Content-Type: application/json

    { "datetime": "2026-02-15T09:00", "appointmentTypeID": 123, "firstName": "John", "lastName": "Doe", "email": "john.doe@example.com", "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:

    python <<'EOF'
    import urllib.request, os, json
    data = json.dumps({
        'datetime': '2026-02-15T09:00',
        'appointmentTypeID': 123,
        'firstName': 'John',
        'lastName': 'Doe',
        'email': 'john.doe@example.com'
    }).encode()
    req = urllib.request.Request('https://api.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

    PUT /acuity-scheduling/api/v1/appointments/{id}
    Content-Type: application/json

    { "firstName": "Jane", "lastName": "Smith", "email": "jane.smith@example.com" }

    #### Cancel Appointment

    PUT /acuity-scheduling/api/v1/appointments/{id}/cancel
    

    Returns the canceled appointment with canceled: true.

    #### Reschedule Appointment

    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

    GET /acuity-scheduling/api/v1/calendars
    

    Response:

    [
      {
        "id": 13499175,
        "name": "Chris",
        "email": "",
        "replyTo": "chris@example.com",
        "description": "",
        "location": "",
        "timezone": "America/Los_Angeles"
      }
    ]
    

    Appointment Types

    #### List Appointment Types

    GET /acuity-scheduling/api/v1/appointment-types
    

    Query Parameters:

  • includeDeleted (boolean) - Include deleted types
  • Response:

    [
      {
        "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

    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:

    [
      {"date": "2026-02-09"},
      {"date": "2026-02-10"},
      {"date": "2026-02-11"}
    ]
    

    #### Get Available Times

    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:

    [
      {"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

    GET /acuity-scheduling/api/v1/clients
    

    Query Parameters:

  • search - Filter by first name, last name, or phone
  • Example:

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.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:

    [
      {
        "firstName": "Jane",
        "lastName": "McTest",
        "email": "jane.mctest@example.com",
        "phone": "(123) 555-0101",
        "notes": ""
      }
    ]
    

    #### Create Client

    POST /acuity-scheduling/api/v1/clients
    Content-Type: application/json

    { "firstName": "John", "lastName": "Doe", "email": "john@example.com", "phone": "555-123-4567" }

    #### Update Client

    PUT /acuity-scheduling/api/v1/clients
    Content-Type: application/json

    { "firstName": "John", "lastName": "Doe", "email": "john.updated@example.com" }

    Note: Client update/delete only works for clients with existing appointments.

    #### Delete Client

    DELETE /acuity-scheduling/api/v1/clients
    Content-Type: application/json

    { "firstName": "John", "lastName": "Doe" }

    Blocks

    #### List Blocks

    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

    GET /acuity-scheduling/api/v1/blocks/{id}
    

    #### Create Block

    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:

    {
      "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

    DELETE /acuity-scheduling/api/v1/blocks/{id}
    

    Returns 204 No Content on success.

    Forms

    #### List Forms

    GET /acuity-scheduling/api/v1/forms
    

    Response:

    [
      {
        "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

    GET /acuity-scheduling/api/v1/labels
    

    Response:

    [
      {"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:

    # 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

    const response = await fetch(
      'https://api.maton.ai/acuity-scheduling/api/v1/appointments?max=10',
      {
        headers: {
          'Authorization': Bearer ${process.env.MATON_API_KEY}
        }
      }
    );
    const appointments = await response.json();
    

    Python

    import os
    import requests

    response = requests.get( 'https://api.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:

    echo $MATON_API_KEY
    

    2. Verify the API key is valid by listing connections:

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.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://api.maton.ai/acuity-scheduling/api/v1/appointments
  • Incorrect: https://api.maton.ai/api/v1/appointments
  • Resources

  • Acuity Scheduling API Quick Start
  • Appointments API
  • Availability API
  • Calendars API
  • Clients API
  • OAuth2 Documentation
  • Maton Community
  • Maton Support
  • πŸ’‘ Examples

    # List appointments
    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://api.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
    

    πŸ“‹ Tips & Best Practices

  • 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.