Creating Appointments
Create a new appointment against a configured calendar window using POST /v1/appointments. The request is validated against availability, slot capacity, and duplicate rules before the booking is confirmed.
Before You Begin
Your API key requires the appointments:write scope. Make sure the following are configured in your HuskyVoice dashboard before calling this endpoint:
- At least one Service (appointment type)
- At least one Branch with Calendar Windows set up for the relevant days and sessions
- The correct timezone set in your org configuration (see Appointments Overview)
Creating an Appointment
- Endpoint:
POST https://api.huskyvoice.ai/v1/appointments - Required scope:
appointments:write
- cURL
- Python
- JavaScript
- n8n
curl -s -X POST https://api.huskyvoice.ai/v1/appointments \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"appointment_type": "General Checkup",
"appointment_date": "2026-06-15T09:30:00.000Z",
"patient_name": "Aadhi",
"parent_phone": "+919840XXXXXX",
"session": "Morning",
"branch_id": "branch_uuid_here"
}'
import requests
url = "https://api.huskyvoice.ai/v1/appointments"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"appointment_type": "General Checkup",
"appointment_date": "2026-06-15T09:30:00.000Z",
"patient_name": "Aadhi",
"parent_phone": "+919840XXXXXX",
"session": "Morning",
"branch_id": "branch_uuid_here"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const response = await fetch("https://api.huskyvoice.ai/v1/appointments", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
appointment_type: "General Checkup",
appointment_date: "2026-06-15T09:30:00.000Z",
patient_name: "Aadhi",
parent_phone: "+919840XXXXXX",
session: "Morning",
branch_id: "branch_uuid_here"
})
});
const data = await response.json();
console.log(data);
Create an HTTP Header Auth credential in n8n: set Name to Authorization and Value to Bearer YOUR_API_KEY. Select it in the HTTP Request node's Authentication field.
{
"name": "HuskyVoice – Create Appointment",
"nodes": [
{
"parameters": {
"method": "POST",
"url": "https://api.huskyvoice.ai/v1/appointments",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{\n \"appointment_type\": \"General Checkup\",\n \"appointment_date\": \"2026-06-15T09:30:00.000Z\",\n \"patient_name\": \"Aadhi\",\n \"parent_phone\": \"+919840XXXXXX\",\n \"session\": \"Morning\",\n \"branch_id\": \"branch_uuid_here\"\n}"
},
"id": "1",
"name": "Create Appointment",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [250, 300]
}
],
"connections": {},
"settings": {},
"meta": { "instanceId": "huskyvoice-docs" }
}
Response — 201 Created
{
"success": true,
"appointment_id": "appt_a1b2c3d4e5",
"token": null,
"data": {
"appointment_id": "appt_a1b2c3d4e5",
"appointment_type": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"branch_id": "branch_uuid_here",
"date": "2026-06-15",
"session": "Morning",
"batch": "MA",
"token": null,
"patient_name": "Aadhi",
"parent_phone": "+919840XXXXXX",
"assigned_doctor": null,
"status": "confirmed",
"external_reference_id": null,
"created_at": "2026-05-26T10:00:00.000Z",
"updated_at": "2026-05-26T10:00:00.000Z"
}
}
Request Fields
| Field | Required | Description |
|---|---|---|
appointment_type | Yes | Service UUID or human-readable name (e.g. "General Checkup") — resolved case-insensitively |
appointment_date | Yes | ISO 8601 UTC datetime (e.g. "2026-06-15T09:30:00.000Z") — time component required |
patient_name | Yes | Patient's full name |
parent_phone | Yes | Patient's phone number |
branch_id | Conditional | Required when your organization has more than one branch; auto-resolved if only one exists. Find your branch IDs via GET /v1/appointment-slots/availability or from Dashboard → Settings → Branches |
session | No | "Morning", "Afternoon", or "Evening" — used to match the correct calendar window |
batch | No | Specific batch label (e.g. "MA") — auto-populated from the matched calendar window if omitted |
assigned_doctor | No | Name or identifier of the assigned doctor |
external_reference_id | No | Your own unique identifier for idempotency (see below) |
appointment_datePass a full UTC datetime string, not a date-only value. The booking engine converts the time to the org's local timezone (read from GET /v1/appointment-config) and checks it against configured calendar windows. A date-only value like "2026-06-15" resolves to UTC midnight, which will likely fall outside any window.
appointment_typeYou can pass either the service UUID ("f47ac10b-58cc-4372-a567-0e02b2c3d479") or the human-readable name ("General Checkup"). Names are resolved case-insensitively. Use GET /v1/services to list all configured types.
Idempotency
Pass external_reference_id to prevent duplicate bookings on retries. If an active (non-cancelled) appointment already exists for that reference ID within your organization, the API returns the existing record with "idempotent": true and HTTP 200 instead of 201.
{
"success": true,
"idempotent": true,
"appointment_id": "appt_a1b2c3d4e5",
"token": null,
"data": { ... }
}
Validation Rules
The API enforces these rules before confirming a booking:
- Future time —
appointment_datemust be in the future. - Slot availability —
appointment_datemust fall within an active, open calendar window for the specified branch and session. - Capacity — The window must have remaining capacity. Each service type is counted independently.
- No duplicate — Only one active booking per patient phone number per appointment type per date is allowed.
- Valid type —
appointment_typemust resolve to a configured service.
Error Codes
| Status | Code | Cause |
|---|---|---|
400 | VALIDATION_ERROR | Missing required field |
400 | PAST_APPOINTMENT | appointment_date is in the past |
409 | SLOT_FULL | Window has no remaining capacity |
409 | SLOT_INACTIVE | Window is closed (status: "CLOSED") |
409 | DUPLICATE_BOOKING | A future non-cancelled appointment already exists for this patient's phone number. The response includes existing_appointment_id. Only applies when duplicate prevention is enabled in your org settings |
422 | INVALID_APPOINTMENT_TYPE | appointment_type does not match any configured service |
422 | OUTSIDE_AVAILABILITY | appointment_date does not fall within any configured calendar window |
404 | NOT_FOUND | Appointment not found (GET / PATCH only) |
403 | INSUFFICIENT_SCOPE | API key does not have the required scope |