connecting...
Online
--
Registered
--
Browsers
--
Uptime
--
Status
--

Clinic Data

Loading...
Total Bookings
--
Success Rate
--
Failed
--
Avg Duration
--
Daily Trend (7 days)
By Clinic
TimeClinicSystemActionStatusErrorDuration
Select a clinic or click Refresh
TimeClinicPatientContactAppointmentSystemStatus
Loading...
Instances
--
Online
--
Total Clinics
--
Total Browsers
--
ClinicTypeInstanceStatus
Loading...
Every request needs the header x-api-key: YOUR_CLINIC_API_KEY — grab it from the Clinics tab. All bodies are JSON with Content-Type: application/json.

Base URL

https://admin.hookneural.com
Use this as the base URL for all webhook endpoints below. Example: https://admin.hookneural.com/api/webhook/jane/book

GHL Webhooks — Jane

Voice AI webhook endpoints for Jane clinics. URL pattern: /api/webhook/jane/{action}
POST /api/webhook/jane/book Book appointment
{
  "customData": {
    "staff_member": "info@drsiva.ca",
    "treatment_name": "Free Initial Aesthetic Consult (Aesthetics) (30min)"
  },
  "calendar": {
    "startTime": "{{datetime_formatter.1.datetime}}",
    "endTime": "{{datetime_formatter.2.datetime}}",
    "selectedTimezone": "America/Toronto",
    "appointmentId": "{{appointment.id}}"
  },
  "first_name": "{{contact.first_name}}",
  "last_name": "{{contact.last_name}}",
  "email": "{{contact.email}}",
  "phone": "{{contact.phone}}"
}
staff_member — staff email address or full name (e.g. "info@drsiva.ca" or "Dr. Smith"). Resolved against Jane staff list. Numeric ID also accepted.
treatment_name — treatment name or partial match (e.g. "Free Initial Aesthetic Consult"). Also accepts treatment_num as numeric ID.
Auto-creates patient if not found (searches by email + name match first).
POST /api/webhook/jane/cancel Cancel appointment
{
  "calendar": {
    "appointmentId": "{{appointment.id}}"
  },
  "notifyPatient": true   // optional — sends cancellation notice
}
POST /api/webhook/jane/reschedule Reschedule appointment
{
  "customData": {
    "staff_member": PUT_STAFF_NUMBER   // optional — keeps same if omitted
  },
  "calendar": {
    "appointmentId": "{{appointment.id}}",
    "startTime": "{{datetime_formatter.1.datetime}}",
    "endTime": "{{datetime_formatter.2.datetime}}",
    "selectedTimezone": "PUT_TIME_ZONE"
  },
  "notifyPatient": true       // optional
}
Cancels old appointment, books new one with same patient & treatment at the new time.
POST /api/webhook/jane/patients Search or create patient
// Search
{ "action": "search", "query": "john@example.com" }

// Create (checks for existing by email first)
{
  "action": "create",
  "firstName": "John",
  "lastName": "Doe",
  "email": "john@example.com",   // optional
  "phone": "416-555-1234"       // optional
}
POST /api/webhook/jane/availability Check open slots
{
  "startDate": "2026-04-07",
  "endDate": "2026-04-11",
  "staffMemberIds": [42],   // optional — filter by staff
  "locationId": 1            // optional, default 1
}

GHL Webhooks — Ocean

Voice AI webhook endpoints for OceanMD clinics. URL pattern: /api/webhook/ocean/{action}
POST /api/webhook/ocean/book Book appointment (Playwright RPA)
{
  "firstName": "John",
  "lastName": "Doe",
  "healthCardNumber": "1234567890",
  "dateOfBirth": "01/15/1990",        // MM/DD/YYYY or YYYY-MM-DD
  "date": "2026-04-07",             // YYYY-MM-DD
  "time": "10:00 AM",              // h:mm AM/PM
  "phone": "416-555-1234",          // patient phone number
  "email": "patient@example.com",  // patient email
  "appointmentType": "New Patient",  // optional
  "reasonForVisit": "Consultation",  // optional, default "Consultation"
  "provider": "Dr. Smith"            // optional
}
Uses Playwright to automate the OceanMD booking page with real patient data. Requires a booking URL set on the clinic.
dateOfBirth accepts MM/DD/YYYY (slash) or YYYY-MM-DD (dash). Optional fields can also be sent inside a customData object as appointment_type, reason_for_visit, provider.
POST /api/webhook/ocean/availability Get cached available slots
{
  "maxDays": 7   // optional, default 7
}
Returns cached slot data from the 15-second refresh loop. Also pushed to GHL via {{ custom_values.availability }}.

Direct API — Appointments

Lower-level endpoints. Use the webhook endpoints above for GHL integration.
GET /appointments/:id Get details by ID
GET /appointments/98765
POST /appointments Create & book (low-level)
// With existing patient ID:
{
  "startAt": "2026-04-07T14:00:00-04:00",
  "endAt": "2026-04-07T14:30:00-04:00",
  "staffMemberId": 42,
  "treatmentId": 15,
  "patient": { "id": 12345 },
  "locationId": 1              // optional, default 1
}

// Auto-create patient (searches by email first):
{
  "startAt": "2026-04-07T14:00:00-04:00",
  "endAt": "2026-04-07T14:30:00-04:00",
  "staffMemberId": 42,
  "treatmentId": 15,
  "patient": {
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com"
  }
}
If patient has no id, searches by email to avoid duplicates, then creates if not found.
POST /appointments/:id/cancel Cancel an appointment
POST /appointments/98765/cancel

{
  "notifyPatient": true   // optional — sends cancellation email
}
Also available as DELETE /appointments/:id (same behavior).
POST /appointments/:id/reschedule Reschedule an appointment
POST /appointments/98765/reschedule

{
  "startAt": "2026-04-10T14:00:00-04:00",
  "endAt": "2026-04-10T14:30:00-04:00",
  "staffMemberId": 42,       // optional — keeps same if omitted
  "notifyPatient": true       // optional
}
Cancels the old appointment and books a new one at the specified time. Returns the new appointment details.

Calendar / Schedule

GET /calendar View schedule for a date range
// Query params — no body needed
GET /calendar?startDate=2026-04-07&endDate=2026-04-11

// Filter by staff
GET /calendar?startDate=2026-04-07&endDate=2026-04-11&staffMemberIds=1,5,12
GET /schedule Ocean — cached slots (sub-100ms)
GET /schedule?maxDays=7
Returns cached availability from the 15-second Ocean refresh loop. Faster than /availability.

Patients

POST /patients Create a new patient
{
  "firstName": "John",             // required
  "lastName": "Doe",               // required
  "email": "john@example.com",     // optional
  "phone": "416-555-1234",         // optional
  "city": "Toronto",              // optional
  "province": "ON",              // optional
  "country": "CA",               // optional, default: CA
  "timeZone": "America/Toronto"   // optional, default: America/Toronto
}
GET /patients List all patients
// No body — just GET /patients
GET /patients/search?q=... Search by name, email, or phone
GET /patients/search?q=john@email.com
GET /patients/:id Get patient by ID
GET /patients/12345

Staff

GET /staff List all practitioners
// No body — returns all staff with IDs you need for booking
GET /staff/:id Get staff member by ID
GET /staff/42

Treatments

GET /treatments List all treatment types
// No body — returns all treatments with IDs you need for booking

Health

GET /health No API key needed
// Response:
{
  "status": "ready",
  "uptime": 3642.5,
  "clinics": [
    {
      "slug": "elitemd",
      "browserConnected": true,
      "reconnectCount": 0
    }
  ]
}

GHL Custom Values

The schedule cache pushes Ocean slot data to GoHighLevel as a location custom value every 15 seconds (only when data changes). The voice AI reads this during live calls.
GHL {{ custom_values.availability }} Available time slots (auto-updated)
// Value stored in GHL (JSON string):
{
  "lastUpdated": "2026-04-04T15:30:00Z",
  "days": [
    {
      "date": "2026-04-07",
      "dayOfWeek": "Monday",
      "slots": ["10:00 AM", "11:15 AM", "1:30 PM"]
    },
    {
      "date": "2026-04-08",
      "dayOfWeek": "Tuesday",
      "slots": ["9:00 AM", "10:30 AM", "3:00 PM"]
    }
  ]
}
HOW Setup How it works
1. Schedule cache runs a Playwright browser against the OceanMD
   booking page every 15 seconds

2. Extracts available time slots via the booking page DOM

3. Compares with previous data — only pushes to GHL when
   slots actually change (saves API calls)

4. Pushes JSON to GHL location custom value via:
   PUT /locations/{locationId}/customValues/{fieldId}
   Host: services.leadconnectorhq.com
   Authorization: Bearer {GHL_API_KEY}
   Version: 2021-07-28

5. Voice AI reads it in conversation prompts as:
   {{ custom_values.availability }}
ENV .env Required environment variables
GHL_API_KEY=pit-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
GHL_LOCATION_ID=your-location-id
GHL_SCHEDULE_FIELD_ID=custom-value-field-id
Get these from GHL → Settings → Custom Values. The field ID is the ID of the custom value named "availability".

Health Log

TimeClinicEventDetail
Loading...