Appointments Endpoints
Manage appointments: creation, retrieval, and cancellation.
Creating an appointment consumes 1 credit. Cancelling an appointment refunds 1 credit (handle the refund logic in your own code: see the note under DELETE /appointments/{id}).
POST /appointments
Creates a new appointment. Automatically consumes 1 credit from your organization.
externalUserId: Your own system's identifier to match with your usersworkerId: Staff/professional ID. Required only if the department hasshowAdminsInBooking=true
Request
curl -X POST https://mc-prd.duckdns.org/api/v1/appointments \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"departmentId": 5,
"dateTime": "2026-02-15T10:00:00",
"name": "Amadou Diallo",
"workerId": 42,
"externalUserId": "customer_12345"
}'
import com.moncreneau.Moncreneau;
import com.moncreneau.exceptions.MoncreneauException;
import java.util.Map;
Moncreneau client = new Moncreneau("your_api_key");
Map<String, Object> data = Map.of(
"departmentId", 5,
"dateTime", "2026-02-15T10:00:00",
"name", "Amadou Diallo",
"workerId", 42,
"externalUserId", "customer_12345"
);
try {
Map<String, Object> appointment = client.appointments.create(data);
System.out.println("Appointment created with ID: " + appointment.get("id"));
System.out.println("QR Code: " + appointment.get("qrCode"));
} catch (MoncreneauException e) {
if ("INSUFFICIENT_CREDITS".equals(e.getErrorCode())) {
System.err.println("Insufficient credits: " + e.getMessage());
}
}
import Moncreneau from '@moncreneau/api';
const client = new Moncreneau('your_api_key');
try {
const appointment = await client.appointments.create({
departmentId: 5,
dateTime: '2026-02-15T10:00:00',
name: 'Amadou Diallo',
workerId: 42,
externalUserId: 'customer_12345'
});
console.log(`Appointment created with ID: ${appointment.id}`);
console.log(`QR Code: ${appointment.qrCode}`);
} catch (error) {
if (error.code === 'INSUFFICIENT_CREDITS') {
console.error('Insufficient credits:', error.message);
}
}
<?php
use Moncreneau\Moncreneau;
use Moncreneau\Exceptions\MoncreneauException;
$client = new Moncreneau('your_api_key');
try {
$appointment = $client->appointments->create([
'departmentId' => 5,
'dateTime' => '2026-02-15T10:00:00',
'name' => 'Amadou Diallo',
'externalUserId' => 'customer_12345'
]);
echo "Appointment created with ID: {$appointment['id']}" . PHP_EOL;
echo "QR Code: {$appointment['qrCode']}" . PHP_EOL;
} catch (MoncreneauException $e) {
if ($e->getErrorCode() === 'INSUFFICIENT_CREDITS') {
echo "Insufficient credits: {$e->getMessage()}" . PHP_EOL;
}
}
from moncreneau import Moncreneau, MoncreneauError
client = Moncreneau('your_api_key')
try:
appointment = client.appointments.create(
department_id=5,
date_time='2026-02-15T10:00:00',
name='Amadou Diallo',
worker_id=42,
external_user_id='customer_12345'
)
print(f"Appointment created with ID: {appointment['id']}")
print(f"QR Code: {appointment['qrCode']}")
except MoncreneauError as e:
if e.code == 'INSUFFICIENT_CREDITS':
print(f"Insufficient credits: {e.message}")
Response 201 - Success
{
"id": 123,
"dateTime": "2026-02-15T10:00:00",
"status": "SCHEDULED",
"name": "Amadou Diallo",
"qrCode": "a1b2c3d4-...",
"departmentId": 5,
"departmentName": "General Consultation",
"externalUserId": "customer_12345",
"createdAt": "2026-01-21T09:30:00"
}
Response 402 - Insufficient Credits
{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits to create appointment. Current: 0, Required: 1"
}
}
Response 400 - Bad Request
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request body is invalid.",
"details": [
{ "field": "dateTime", "message": "must not be null" }
]
}
}
GET /appointments/{id}
Retrieves an appointment's details by ID.
Request
curl https://mc-prd.duckdns.org/api/v1/appointments/123 \
-H "X-API-Key: YOUR_API_KEY"
import com.moncreneau.Moncreneau;
import java.util.Map;
Moncreneau client = new Moncreneau("your_api_key");
Map<String, Object> appointment = client.appointments.retrieve("123");
System.out.println("Status: " + appointment.get("status"));
System.out.println("Date: " + appointment.get("dateTime"));
System.out.println("Name: " + appointment.get("name"));
import Moncreneau from '@moncreneau/api';
const client = new Moncreneau('your_api_key');
const appointment = await client.appointments.retrieve('123');
console.log(`Status: ${appointment.status}`);
console.log(`Date: ${appointment.dateTime}`);
console.log(`Name: ${appointment.name}`);
<?php
use Moncreneau\Moncreneau;
$client = new Moncreneau('your_api_key');
$appointment = $client->appointments->retrieve('123');
echo "Status: {$appointment['status']}" . PHP_EOL;
echo "Date: {$appointment['dateTime']}" . PHP_EOL;
echo "Name: {$appointment['name']}" . PHP_EOL;
from moncreneau import Moncreneau
client = Moncreneau('your_api_key')
appointment = client.appointments.retrieve('123')
print(f"Status: {appointment['status']}")
print(f"Date: {appointment['dateTime']}")
print(f"Name: {appointment['name']}")
Response 200
{
"id": 123,
"dateTime": "2026-02-15T10:00:00",
"status": "SCHEDULED",
"name": "Amadou Diallo",
"qrCode": "a1b2c3d4-...",
"departmentId": 5,
"departmentName": "General Consultation",
"createdAt": "2026-01-21T09:30:00"
}
Response 404
{
"error": {
"code": "APPOINTMENT_NOT_FOUND",
"message": "Appointment not found with id: 123"
}
}
GET /appointments
Lists all appointments for your organization, with pagination and optional filters.
You can filter by status, departmentId, externalUserId, startDate, endDate, and paginate with page and size.
Request
curl -X GET "https://mc-prd.duckdns.org/api/v1/appointments?page=0&size=20&status=SCHEDULED" \
-H "X-API-Key: YOUR_API_KEY"
import com.moncreneau.Moncreneau;
import java.util.Map;
Moncreneau client = new Moncreneau("your_api_key");
// Simple list
Map<String, Object> page = client.appointments.list(Map.of());
// With filters
Map<String, Object> filtered = client.appointments.list(Map.of(
"status", "SCHEDULED",
"departmentId", "5",
"externalUserId", "customer_12345",
"page", "0",
"size", "20"
));
System.out.println("Total: " + filtered.get("totalElements"));
import Moncreneau from '@moncreneau/api';
const client = new Moncreneau('your_api_key');
// Simple list
const page = await client.appointments.list();
// With filters
const filtered = await client.appointments.list({
page: 0,
size: 20,
status: 'SCHEDULED',
departmentId: '5',
externalUserId: 'customer_12345',
startDate: '2026-02-01T00:00:00',
endDate: '2026-02-28T23:59:59'
});
console.log(`Total: ${filtered.totalElements}`);
filtered.appointments.forEach(apt => {
console.log(`${apt.name} - ${apt.dateTime}`);
});
<?php
use Moncreneau\Moncreneau;
$client = new Moncreneau('your_api_key');
// Simple list
$page = $client->appointments->list();
// With filters
$filtered = $client->appointments->list([
'page' => 0,
'size' => 20,
'status' => 'SCHEDULED',
'departmentId' => 5,
'externalUserId' => 'customer_12345',
'startDate' => '2026-02-01T00:00:00',
'endDate' => '2026-02-28T23:59:59'
]);
echo "Total: {$filtered['totalElements']}" . PHP_EOL;
foreach ($filtered['appointments'] as $apt) {
echo "{$apt['name']} - {$apt['dateTime']}" . PHP_EOL;
}
from moncreneau import Moncreneau
client = Moncreneau('your_api_key')
# Simple list
page = client.appointments.list()
# With filters
filtered = client.appointments.list(
page=0,
size=20,
status='SCHEDULED',
department_id='5',
external_user_id='customer_12345',
start_date='2026-02-01T00:00:00',
end_date='2026-02-28T23:59:59'
)
print(f"Total: {filtered['totalElements']}")
for apt in filtered['appointments']:
print(f"{apt['name']} - {apt['dateTime']}")
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 0 | Page number (starts at 0) |
size | integer | 20 | Items per page (max 100) |
status | string | - | Filter by status (SCHEDULED, COMPLETED, CANCELLED, MISSED) |
departmentId | integer | - | Filter by department ID |
externalUserId | string | - | Filter by your external user ID |
startDate | string (ISO 8601) | - | Appointments after this date |
endDate | string (ISO 8601) | - | Appointments before this date |
Response 200
{
"appointments": [
{
"id": 123,
"dateTime": "2026-02-15T10:00:00",
"status": "SCHEDULED",
"name": "Amadou Diallo",
"qrCode": "a1b2c3d4-...",
"departmentId": 5,
"departmentName": "General Consultation",
"externalUserId": "customer_12345",
"createdAt": "2026-01-21T09:30:00"
}
],
"page": 0,
"size": 20,
"totalElements": 45,
"totalPages": 3,
"isLast": false
}
DELETE /appointments/{id}
Cancels (archives) an appointment.
This endpoint archives the appointment — it does not change its status (which stays SCHEDULED), and does not automatically refund a credit today, unlike cancelling from the web dashboard. The response is a 200 with no body.
Request
curl -X DELETE https://mc-prd.duckdns.org/api/v1/appointments/123 \
-H "X-API-Key: YOUR_API_KEY"
import com.moncreneau.Moncreneau;
Moncreneau client = new Moncreneau("your_api_key");
client.appointments.cancel("123");
System.out.println("Appointment archived");
import Moncreneau from '@moncreneau/api';
const client = new Moncreneau('your_api_key');
await client.appointments.cancel('123');
console.log('Appointment archived');
<?php
use Moncreneau\Moncreneau;
$client = new Moncreneau('your_api_key');
$client->appointments->cancel('123');
echo "Appointment archived" . PHP_EOL;
from moncreneau import Moncreneau
client = Moncreneau('your_api_key')
client.appointments.cancel('123')
print('Appointment archived')
Response 200
Empty body.
Response 404
{
"error": {
"code": "APPOINTMENT_NOT_FOUND",
"message": "Appointment not found with id: 123"
}
}
Error Handling
All errors return a standardized envelope:
{
error: {
code: string; // Error code (e.g. INSUFFICIENT_CREDITS)
message: string; // Human-readable message
details?: Array<{ // Only present for validation errors (400)
field: string;
message: string;
}>;
}
}
Common error codes
| Code | HTTP | Description |
|---|---|---|
INSUFFICIENT_CREDITS | 402 | Not enough credits to create an appointment |
APPOINTMENT_NOT_FOUND | 404 | Appointment not found |
VALIDATION_ERROR | 400 | Invalid request body (see details) |
INVALID_DATE_FORMAT | 400 | Malformed date (startDate/endDate) |
MISSING_API_KEY / INVALID_API_KEY | 401 | API key missing, invalid, or revoked |
INSUFFICIENT_SCOPE | 403 | Insufficient scope for this operation |
RATE_LIMIT_EXCEEDED | 429 | Requests-per-hour limit exceeded |
INTERNAL_ERROR | 500 | Internal server error |
See Error Handling for full details.