REST API Reference

All calls with parameters, status codes and schemas.

This page describes the API in full. If you are setting the API up for the first time, better start with the step-by-step guide.

The base address is /api on your own installation, in the examples therefore https://example.com/api. All calls are made from your server, not from your customers' browsers: no CORS headers are sent, and the token must not be built into a website or an app.

On this page

Authentication

Every call needs a token. You generate it in the admin area under Configuration → API. The token starts with apm_, followed by 64 characters, and is shown only once. There is exactly one token per installation: a new token invalidates the previous one immediately.

Authorization: Bearer apm_your-token

Without a valid token every call answers with 401 {"error":"Unauthorized"}. If the API is not activated in the admin area, it answers with 503 API disabled.

GET/schedules

Returns all appointment calendars of the installation. You use the returned id values as the parameter schedule in all further calls.

Status codes

StatusMeaning
200 List of the appointment calendars
401 Token is missing or invalid
429 Request limit reached
503 The API is not activated or the installation is not yet complete

Response 200

{
    "data": [
        { "id": 1, "name": "Main location" },
        { "id": 2, "name": "Branch" }
    ]
}

Call with curl

curl -H "Authorization: Bearer apm_your-token" \
  https://example.com/api/schedules

GET/reasons

Returns the appointment reasons (services) of an appointment calendar. If no appointment reasons are set up for the calendar, data is an empty array. duration is the duration in seconds.

Query parameters

NameTypeRequiredDescriptionExample
schedule integer ≥ 1 required Number of the appointment calendar from GET /schedules 1

Status codes

StatusMeaning
200 List of the appointment reasons (can be empty)
401 Token is missing or invalid
404 Appointment calendar not found
429 Request limit reached
503 The API is not activated or the installation is not yet complete

Response 200

{
    "data": [
        {
            "id": 1,
            "name": "Consultation",
            "description": "Standard consultation",
            "duration": 1800
        },
        {
            "id": 2,
            "name": "Follow-up appointment",
            "description": "",
            "duration": 900
        }
    ]
}

Call with curl

curl -H "Authorization: Bearer apm_your-token" \
  "https://example.com/api/reasons?schedule=1"

GET/days

Returns the days on which at least one time is free for this appointment calendar and appointment reason. The format is YYYY-MM-DD. How far the list reaches into the future is determined by the settings of the appointment calendar.

Query parameters

NameTypeRequiredDescriptionExample
schedule integer ≥ 1 required Number of the appointment calendar 1
reason integer ≥ 1 required Number of the appointment reason from GET /reasons 1

Status codes

StatusMeaning
200 List of the days with free appointments
401 Token is missing or invalid
404 Appointment calendar or appointment reason not found
429 Request limit reached
503 The API is not activated or the installation is not yet complete

Response 200

{
    "data": ["2026-05-23", "2026-05-24", "2026-05-26"]
}

Call with curl

curl -H "Authorization: Bearer apm_your-token" \
  "https://example.com/api/days?schedule=1&reason=1"

GET/slots

Returns the free times of a day. The times are local times of the installation, the format is YYYY-MM-DD HH:MM:SS. If nothing is free on that day, data is an empty array.

Query parameters

NameTypeRequiredDescriptionExample
schedule integer ≥ 1 required Number of the appointment calendar 1
reason integer ≥ 1 required Number of the appointment reason 1
day string required Day in the format YYYY-MM-DD from GET /days 2026-05-23

Status codes

StatusMeaning
200 List of the free times (can be empty)
401 Token is missing or invalid
404 Appointment calendar, appointment reason or day not found
429 Request limit reached
503 The API is not activated or the installation is not yet complete

Response 200

{
    "data": [
        "2026-05-23 09:00:00",
        "2026-05-23 09:30:00",
        "2026-05-23 10:00:00"
    ]
}

Call with curl

curl -H "Authorization: Bearer apm_your-token" \
  "https://example.com/api/slots?schedule=1&reason=1&day=2026-05-23"

GET/forms

Returns the form fields that have to be filled in to book this time. You use the field names as keys in the object submission of POST /bookings. Always query the fields instead of hard-coding them in your own program. The field password is never returned.

Query parameters

NameTypeRequiredDescriptionExample
schedule integer ≥ 1 required Number of the appointment calendar 1
reason integer ≥ 1 required Number of the appointment reason 1
slot string required Time in the format YYYY-MM-DD HH:MM:SS. The blank has to be encoded as %20. 2026-05-23%2009:00:00

Status codes

StatusMeaning
200 Form fields, keyed by field name
401 Token is missing or invalid
404 Appointment calendar, appointment reason or time not found
429 Request limit reached
503 The API is not activated or the installation is not yet complete

Response 200

{
    "data": {
        "first_name": {
            "form_type": "textbox",
            "input_type": "text",
            "label": "First name",
            "required": true,
            "value": ""
        },
        "last_name": {
            "form_type": "textbox",
            "input_type": "text",
            "label": "Last name",
            "required": true,
            "value": ""
        },
        "email": {
            "form_type": "textbox",
            "input_type": "email",
            "label": "Email address",
            "required": false,
            "value": ""
        },
        "phone": {
            "form_type": "textbox",
            "input_type": "tel",
            "label": "Phone number",
            "required": false,
            "value": ""
        }
    }
}

Call with curl

curl -H "Authorization: Bearer apm_your-token" \
  "https://example.com/api/forms?schedule=1&reason=1&slot=2026-05-23%2009:00:00"

POST/bookings

Creates an appointment. First query the form fields through GET /forms and send their values in the object submission. The header must contain Content-Type: application/json.

Fields in the request body

NameTypeRequiredDescriptionExample
schedule integer ≥ 1 required Number of the appointment calendar 1
reason integer ≥ 1 required Number of the appointment reason 1
slot string required Time in the format YYYY-MM-DD HH:MM:SS, exactly 19 characters 2026-05-23 09:00:00
submission object required Values for the field names from GET /forms

Request body

{
    "schedule": 1,
    "reason": 1,
    "slot": "2026-05-23 09:00:00",
    "submission": {
        "first_name": "Hans",
        "last_name": "Pitt",
        "email": "hans.pitt@example.com",
        "phone": "+49 30 1234567"
    }
}

Status codes

StatusMeaning
201 The appointment has been created
400 Invalid request, missing required field or invalid JSON
401 Token is missing or invalid
404 Appointment calendar, appointment reason or time not found
415 Content-Type: application/json is missing
429 Request limit reached
500 Customer record or appointment could not be saved
503 The API is not activated or the installation is not yet complete

Response 201

{
    "booking_id": 142,
    "booking_details_id": "a3f8c2d1e5b6",
    "user_id": 87,
    "slot": "2026-05-23T09:00:00Z"
}

Response 400 for a missing required field

{
    "error": "Field is required",
    "field": "email"
}

Call with curl

curl -X POST https://example.com/api/bookings \
  -H "Authorization: Bearer apm_your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "schedule": 1,
    "reason": 1,
    "slot": "2026-05-23 09:00:00",
    "submission": {
        "first_name": "Hans",
        "last_name": "Pitt",
        "email": "hans.pitt@example.com"
    }
  }'

Schemas

The data structures that appear in the responses.

Schedule

{
    "id": integer,
    "name": string
}

Reason

{
    "id": integer,
    "name": string,
    "description": string,
    "duration": integer   // seconds
}

FormField

{
    "form_type": string,
    "input_type": string,
    "label": string,
    "required": boolean,
    "value": any
}

BookingRequest

{
    "schedule": integer,
    "reason": integer,
    "slot": "YYYY-MM-DD HH:MM:SS",
    "submission": {
        "<fieldname>": <value>
    }
}

BookingResponse

{
    "booking_id": integer,
    "booking_details_id": string,
    "user_id": integer,
    "slot": "2026-05-23T09:00:00Z"   // UTC, ISO 8601
}

Error / BookingError

{
    "error": string,
    "field": string   // optional
}

Common error responses

These responses can occur with every call.

StatusMeaningExplanation
401 Unauthorized The token is missing, is wrong or has been replaced by a new one. Some servers strip the Authorization header; ask your provider if in doubt.
404 Not Found The requested appointment calendar, appointment reason, day or time is no longer available. A missing or wrongly formatted parameter also produces 404, not 400.
429 Too Many Requests The limit of 300 requests per minute and token is reached. The header Retry-After names the waiting time in seconds.
503 Service Unavailable The API is not activated in the admin area (API disabled) or the installation is not yet complete (Not configured). Both cases affect every call.

Errors are always returned as JSON and always have the same shape:

{ "error": "Description of the error" }

For a booking, a validation error names the field concerned as well:

{ "error": "Field is required", "field": "email" }

The complete list of error texts per call is part of the guide.

Machine-readable description

All calls are described as an OpenAPI file as per version 3.1 as well. With it you generate client libraries or load the API into tools such as Postman, Insomnia or Swagger UI.

View openapi.json

In the file the address /api is entered under servers. This is deliberately a relative entry, so that the file is valid on every installation. In your tool please enter the address of your own scheduler, for example https://example.com/api. The same file is part of your installation as well, under /api/openapi.json.

Back to the guide.

Back to Top