Booking Flow

Consumer-facing endpoints for appointment booking. These endpoints are also used by the BookingJS widget and are optimized for frontend integrations.

No authentication required

The consumer booking endpoints don't require an API key. They are publicly accessible, since they are intended for end consumers. Access control is handled via channel settings and resource references.

Overview

The standard booking flow consists of three steps:

  1. Retrieve available appointments - list of all bookable slots
  2. Reserve appointment - 3-minute hold on the selected slot
  3. Complete booking - finalize the appointment with consumer data
MethodEndpointDescription
GET/resources/:ref/upcoming_bookablesRetrieve available appointments
POST/rest/1/resources/:ref/reserve_appointmentReserve appointment (3 min)
POST/resources/:ref/create_appointment_with_consumerFinalize booking
POST/products/active_productsRetrieve active products
POST/resources/public_dataPublic resource data
OPTIONS/resources/:ref/upcoming_bookablesCORS preflight

1. Retrieve Available Appointments

Retrieves all bookable time slots for one or more resources. The results are grouped by a configurable date format to make a two-level UI (e.g. month view → day list) easy to implement.

Endpoint
GET /resources/{ref}/upcoming_bookables

Path Parameters

ParameterTypeDescription
refstringResource reference or UUID. Formats: resourceId@providerUuid@platform - full reference; resourceId@platform - short form; uuid - direct UUID of the resource

Query Parameters

ParameterTypeRequiredDescription
groupFormatstringNoJoda-Time format for grouping. All bookables with the same value end up in one group. Default: yyyy-MM-dd. Examples: MM-yyyy (monthly), MMMM (month name)
timeFormatstringNoFormat for formattedStart/formattedEnd. Default: yyyy-MM-dd HH:mm
languageTagstringNoIETF BCP 47 language tag for server-side translation (e.g. month names). Example: de_DE, fr_FR
channelKeystringNoBooking channel. Default: RESOURCE_PUBLIC. See Channel Keys
refstringNoAdditional resource references. Can be specified multiple times to load bookables for several resources at once
prdRefstringNoProduct reference or UUID. Filters to bookables that support this product. Also takes the product's leadTime/followUpTime into account

Request

Example: monthly grouping in French
curl -X GET "https://www.timum.de/resources/my-resource@myPlatform/upcoming_bookables?groupFormat=MMMM&languageTag=fr_FR"

Response

The response is an object with dynamic keys based on the groupFormat. It also includes a public_visible flag.

Response (200 OK)
{
  "avril 18": [
    {
      "formattedStart": "2018-04-30 14:00",
      "formattedEnd": "2018-04-30 14:30",
      "start": "2018-04-30T14:00:00+02:00",
      "end": "2018-04-30T14:30:00+02:00",
      "timeslot_uuid": "6cb6df60-48d8-11e8-a5e5-263fa1a58213",
      "product_uuid": "7fc85970-a2d0-11e2-9cd0-1231430706c1",
      "resource_uuid": "636627f0-006c-11ec-a5c8-02e4d9518b64",
      "product_name": "Gesellschaftsspiele spielen",
      "resource_name": "2nd Level Support",
      "contact_channel": null,
      "capacity": 1,
      "capacity_left": 1,
      "products": [],
      "kind": "models.Bookable"
    }
  ],
  "mai 18": [
    {
      "appointment_uuid": "864b80c0-483f-11f0-b6e3-72fe2304273f",
      "formattedStart": "2018-05-02 14:00",
      "formattedEnd": "2018-05-02 14:30",
      "start": "2018-05-02T14:00:00+02:00",
      "end": "2018-05-02T14:30:00+02:00",
      "timeslot_uuid": "267b2d70-48d9-11e8-a5e5-263fa1a58213",
      "product_uuid": "0bd09a60-1d8f-11e9-bf75-06ecf2a1ba22",
      "resource_uuid": "636627f0-006c-11ec-a5c8-02e4d9518b64",
      "product_name": "Video Call 30",
      "resource_name": "2nd Level Support",
      "contact_channel": {
        "type": "location",
        "value": "Telefon und Bildschirmfreigabe (wir rufen Sie an)"
      },
      "capacity": 5,
      "capacity_left": 3,
      "products": [
        { "uuid": "0bd09a60-1d8f-11e9-bf75-06ecf2a1ba22", "name": "Video Call 30" }
      ],
      "kind": "models.LotAppointment"
    }
  ],
  "public_visible": true
}

Bookable Types

kindMeaningNotes
models.BookableSlot from an availability (timeslot)Becomes a LotAppointment on the first booking. Use timeslot_uuid for reserve/create
models.LotAppointmentExisting group appointment with remaining capacityAppointment that has already been created. Use appointment_uuid for reserve/create

Bookable vs LotAppointment

A models.Bookable is a potential slot from an availability. As soon as the first consumer books it, it becomes a models.LotAppointment with a new appointment_uuid. For further bookings of the same slot, you must use this new UUID!

Response Fields

FieldTypeDescription
start / endstringISO 8601 timestamp with time zone
formattedStart / formattedEndstringTime formatted according to timeFormat
timeslot_uuidstringUUID of the underlying availability
appointment_uuidstring?UUID of the appointment (only for LotAppointment)
product_uuidstring?UUID of the product, or null
resource_uuidstringUUID of the resource
capacitynumberTotal capacity of the slot
capacity_leftnumberRemaining free spots
contact_channelobject?Contact channel with type and value
productsarrayList of available products for this slot
kindstringmodels.Bookable or models.LotAppointment

Status Codes

CodeMeaning
200Success, bookables returned
204No bookables available (empty response)

2. Reserve Appointment

Temporarily reserves an appointment for 3 minutes. During this time, the slot can only be booked by the customer who made the reservation. This prevents double bookings while the form is being filled out.

Endpoint
POST /rest/1/resources/{ref}/reserve_appointment

Always call before booking

Always call this endpoint before using create_appointment_with_consumer! Even after the 3 minutes have expired, you can still complete the booking - but if another customer was faster, it will fail.

Query Parameters

ParameterTypeRequiredDescription
refstringNoResource or channel reference
channelKeystringNoBooking channel. Default: RESOURCE_PUBLIC

Request Body

FieldTypeRequiredDescription
timeslot_uuidstringConditional*UUID of the timeslot (availability). Use for models.Bookable. Applies the availability's default settings to the new appointment
appointment_uuidstringConditional*UUID of the existing appointment. Required for models.LotAppointment
product_uuidstringYesUUID of the product to be booked
fromstringYesStart time of the bookable (ISO 8601, UTC)
tostringYesEnd time of the bookable (ISO 8601, UTC)

* For models.Bookable, send timeslot_uuid. For models.LotAppointment, appointment_uuid is required.

Request

Reserve appointment
curl -X POST "https://www.timum.de/rest/1/resources/my-resource@myPlatform/reserve_appointment" \
  -H "Content-Type: application/json" \
  -d '{
    "timeslot_uuid": "6cb6df60-48d8-11e8-a5e5-263fa1a58213",
    "product_uuid": "7fc85970-a2d0-11e2-9cd0-1231430706c1",
    "from": "2025-01-15T13:00:00Z",
    "to": "2025-01-15T13:30:00Z"
  }'

Response

Response (200 OK)
{
  "api-info": { "version": "1" },
  "participation": {
    "uuid": "a48dcf00-483c-11f0-b6e3-72fe2304273f",
    "appointment_uuid": "a48d0bb0-483c-11f0-b6e3-72fe2304273f",
    "timeslot_uuid": "a48e6b40-483c-11f0-b6e3-72fe2304273f",
    "resource_uuid": "636627f0-006c-11ec-a5c8-02e4d9518b64",
    "product_uuid": "0bd09a60-1d8f-11e9-bf75-06ecf2a1ba22",
    "from": "2025-06-16T12:25:00Z",
    "to": "2025-06-16T12:55:00Z",
    "appointment_capacity": 1,
    "appointment_capacity_left": 0,
    "customer_uuid": "a48df610-483c-11f0-b6e3-72fe2304273f",
    "customer_mobile": null,
    "customer_fullName": null,
    "customer_email": null,
    "customer_note": null,
    "state": "RESERVED",
    "formatedAddress": "Telefon und Bildschirmfreigabe (wir rufen Sie an)",
    "messages": []
  },
  "appointments": [
    {
      "uuid": "a48d0bb0-483c-11f0-b6e3-72fe2304273f",
      "kind": "models.LotAppointment",
      "product_id": "0bd09a60-1d8f-11e9-bf75-06ecf2a1ba22",
      "product_name": "Video Call 30",
      "resource_id": "636627f0-006c-11ec-a5c8-02e4d9518b64",
      "from": "2025-06-16T12:25:00Z",
      "to": "2025-06-16T12:55:00Z",
      "state": "ACTIVE",
      "capacity": 1,
      "capacity_left": 0,
      "customers": [
        {
          "customer_placeholder_id": "a48df610-483c-11f0-b6e3-72fe2304273f",
          "customer_uuid": "a48df610-483c-11f0-b6e3-72fe2304273f",
          "participationState": "RESERVED",
          "participation_id": "a48dcf00-483c-11f0-b6e3-72fe2304273f"
        }
      ]
    }
  ]
}

Save customer_uuid

Save participation.customer_uuid from the response! You will need this value as placeholder_id for the create_appointment_with_consumer call.

Reservation Behavior

  • The reservation is valid for 3 minutes
  • The state is RESERVED
  • After it expires, the reservation is automatically deleted
  • capacity_left is reduced while the reservation is active
  • You can still book even after the timeout - but without protection against double booking

3. Finalize Booking

Completes the booking with the consumer's data. If a user with the given email or phone number already exists, the appointment is assigned to that account. Otherwise, a new account is created.

Endpoint
POST /resources/{ref}/create_appointment_with_consumer

Query Parameters

ParameterTypeRequiredDescription
timeFormatstringNoFormat for time values in the response

Request Body

FieldTypeRequiredDescription
startstringYesStart time (ISO 8601)
endstringYesEnd time (ISO 8601)
timeslot_uuidstringYesUUID of the timeslot or appointment
product_uuidstringNoUUID of the product
placeholder_idstringNo*participation.customer_uuid from the reserve response. Identifies the reservation
emailstringYesConsumer's email
firstnamestringYesConsumer's first name
lastnamestringYesConsumer's last name
mobilestringNoConsumer's mobile number
messagestringNoOptional message (max. 1024 characters)
localestringNoLanguage code (e.g. de, en). Determines the language of transactional emails
channelKeystringNoBooking channel. Default: RESOURCE_PUBLIC

* placeholder_id is technically optional, but you should always send it to make sure your user's reservation is used.

Request

Complete booking
curl -X POST "https://www.timum.de/resources/my-resource@myPlatform/create_appointment_with_consumer" \
  -H "Content-Type: application/json" \
  -d '{
    "start": "2025-01-15T13:00:00Z",
    "end": "2025-01-15T13:30:00Z",
    "timeslot_uuid": "6cb6df60-48d8-11e8-a5e5-263fa1a58213",
    "product_uuid": "7fc85970-a2d0-11e2-9cd0-1231430706c1",
    "placeholder_id": "a48df610-483c-11f0-b6e3-72fe2304273f",
    "channelKey": "RESOURCE_PUBLIC",
    "email": "max@example.com",
    "firstname": "Max",
    "lastname": "Mustermann",
    "mobile": "0173 1234567",
    "locale": "de",
    "message": "Ich freue mich auf den Termin."
  }'

Response (Success)

Response (201 Created)
{
  "api-info": { "version": "1" },
  "createdAppointment": {
    "appointment_uuid": "864b80c0-483f-11f0-b6e3-72fe2304273f",
    "start": "2025-06-17T11:05:00+02:00",
    "end": "2025-06-17T12:05:00+02:00",
    "timeslot_uuid": "864c4410-483f-11f0-b6e3-72fe2304273f",
    "product_uuid": "0bd09a60-1d8f-11e9-bf75-06ecf2a1ba22",
    "resource_uuid": "636627f0-006c-11ec-a5c8-02e4d9518b64",
    "contact_channel": {
      "type": "location",
      "value": "Telefon und Bildschirmfreigabe (wir rufen Sie an)"
    },
    "product_name": "Video Call 30",
    "resource_name": "2nd Level Support",
    "capacity": 1,
    "capacity_left": 0,
    "products": [
      { "uuid": "0bd09a60-1d8f-11e9-bf75-06ecf2a1ba22", "name": "Video Call 30" }
    ],
    "kind": "models.LotAppointment",
    "cancelLink": "https://www.timum.de/rebook/6366c430-006c-11ec-a5c8-02e4d9518b64?..."
  }
}

cancelLink

The response includes a cancelLink. This signed link allows the consumer to cancel their appointment independently. You can use this link in your confirmation email.

Response (Error)

Response (412 Precondition Failed)
{
  "api-info": { "version": "1" },
  "errors": [
    {
      "errorCode": "201",
      "message": "Das überlappt mit einem anderen Termin."
    }
  ]
}

Algorithm Details

  • If a user with the email or mobile number already exists, the appointment is assigned to that account
  • Missing attributes (firstname, lastname, mobile) are added to the existing user, but not overwritten
  • The new user's language is taken from the CRM actor (or via the locale parameter)
  • For group appointments: the first booking creates the appointment, further bookings increase the number of participants

Status Codes

CodeMeaning
201Appointment created successfully
400Required field missing or invalid
412Slot already booked (errorCode 201)

Troubleshooting

ProblemCauseSolution
"Das überlappt mit einem anderen Termin" (errorCode 201)Slot on an availability already booked. First booking creates a new appointment with a new UUIDUse the new timeslot_uuid from the first booking response for further bookings
"Email missing" even though it's in the bodyRedirect issue due to missing www.Make sure you use https://www.timum.de (with www.)
301 redirect with no responseMissing www. in the URLAlways use https://www.timum.de
AppointmentAlreadyBookedExceptionThe consumer is already participating in this appointmentA user cannot participate in the same appointment twice. Check for duplicates

4. Retrieve Active Products

Retrieves all active/enabled products for a resource. The result list may be filtered depending on the channel settings.

Endpoint
POST /products/active_products

Query Parameters

ParameterTypeRequiredDescription
refstringConditional*Resource or channel reference. Can be specified multiple times
tslRefsstringConditional*Appointment or availability reference. Can be specified multiple times
channelKeystringNoBooking channel. Default: RESOURCE_PUBLIC

* At least ref or tslRefs must be specified.

Request

Retrieve products
curl -X POST "https://www.timum.de/products/active_products?ref=my-resource@myPlatform&channelKey=RESOURCE_PUBLIC"

Response

Response (200 OK)
{
  "products": [
    {
      "uuid": "92867f70-4836-11e5-bc04-021a52c25043",
      "name": "Besichtigung",
      "description": "",
      "minDuration": 30,
      "maxDuration": 45,
      "leadTimeMinutes": 0,
      "followUpTimeMinutes": 20,
      "exclusive": false
    },
    {
      "uuid": "0bb978c0-5740-11eb-8b95-024759471364",
      "name": "Beratungsgespräch",
      "description": "Ausführliches Beratungsgespräch",
      "minDuration": 60,
      "maxDuration": 90,
      "leadTimeMinutes": null,
      "followUpTimeMinutes": null,
      "exclusive": true
    }
  ]
}

Response Fields

FieldTypeDescription
uuidstringUnique product ID
namestringDisplay name of the product
descriptionstringProduct description (for customer notes)
minDurationnumber?Minimum duration in minutes
maxDurationnumber?Maximum duration in minutes
leadTimeMinutesnumber?Lead time (travel/preparation) in minutes
followUpTimeMinutesnumber?Follow-up time (return travel/wrap-up) in minutes
exclusivebooleanWhether the product is exclusive (only for certain channels)

5. Retrieve Public Data

Retrieves public information about the provider, resource, channel settings, and contact person. Useful for rendering booking widgets.

Endpoint
POST /resources/public_data

Query Parameters

ParameterTypeRequiredDescription
refstringConditional*Resource or channel reference. Can be specified multiple times
tslRefsstringConditional*Appointment or availability reference. Can be specified multiple times
channelKeystringNoBooking channel. Default: RESOURCE_PUBLIC

* At least ref or tslRefs must be specified.

Request

Retrieve public data
curl -X POST "https://www.timum.de/resources/public_data?ref=my-resource@myPlatform&channelKey=RESOURCE_PUBLIC"

Response

Response (200 OK)
{
  "contact": {
    "name": "Max Makler",
    "email": "kontakt@example.de",
    "mobile": "0173 1234567",
    "phone": "030 12345678"
  },
  "resource": {
    "uuid": "636627f0-006c-11ec-a5c8-02e4d9518b64",
    "name": "Musterstraße 1",
    "description": "Schöne 3-Zimmer-Wohnung mit Balkon",
    "contactChannelType": "",
    "msgHelpText": "",
    "url": "https://example.com/expose/123",
    "imgUrl": "https://cdn.example.com/images/123.jpg"
  },
  "provider": {
    "name": "Mustermakler GmbH",
    "description": "Ihr Partner für Immobilien in Berlin",
    "isThemingAllowed": true,
    "isLocalisationAllowed": true,
    "areCustomFieldsAllowed": true
  },
  "channel": {
    "bookingProcess": "IMMEDIATE"
  }
}

Response Structure

contact

FieldDescription
nameName of the contact person (from contact profile)
emailPublic email address
mobileMobile number
phoneLandline number

resource

FieldDescription
uuidUnique resource ID
namePublic name of the resource
descriptionDescription of the resource
urlExternal URL (e.g. link to the property listing)
imgUrlImage URL of the resource

provider

FieldDescription
nameCalendar/company name
descriptionDescription of the provider
isThemingAllowedWhether custom theming is allowed
isLocalisationAllowedWhether custom localization is allowed
areCustomFieldsAllowedWhether custom fields are allowed

channel

FieldDescription
bookingProcessIMMEDIATE = direct booking, REQUESTED = appointment request

6. CORS Preflight

Browsers automatically send OPTIONS requests before cross-origin requests. timum answers these automatically for all consumer booking endpoints.

Endpoint
OPTIONS /resources/{ref}/upcoming_bookables

Response Headers

CORS Response Headers
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Auth-Token
Access-Control-Max-Age: 36

Automatic CORS support

Cross-origin requests from any origin are accepted. You don't need to configure anything special. Browsers perform these preflight requests automatically.

Channel Keys

timum supports 4 different booking channels. Each channel has its own settings for visibility, booking process, and product filtering.

channelKeyName (UI)Usage
RESOURCE_PUBLICPublic booking linkDefault channel. Can be published publicly
RESOURCE_EXCLUSIVEExclusive booking accessFor accepted customers (address book)
RESOURCE_REFERENCEEmbedded booking calendarFor automatically generated embeds (e.g. real estate portals)
CALENDAR_PUBLICWebsite plugin & overall calendarFor website plugins with all resources

The channel settings can be configured in the timum frontend under Resource → Enable appointment booking.

Booking Processes

ProcessDescription
IMMEDIATEDirect booking. The appointment is confirmed immediately. The consumer receives a confirmation, the provider receives a notification
REQUESTEDAppointment request. The appointment must be confirmed by the provider. The consumer receives "Request received", the provider receives the request for confirmation

Complete Booking Flow

Here is the complete flow for booking an appointment:

Step 1: Load Bookables

curl "https://www.timum.de/resources/immobilie-123@is24/upcoming_bookables?groupFormat=yyyy-MM-dd&prdRef=besichtigung-30min@is24"

Step 2: Reserve Slot

curl -X POST "https://www.timum.de/rest/1/resources/immobilie-123@is24/reserve_appointment" \
  -H "Content-Type: application/json" \
  -d '{
    "timeslot_uuid": "6cb6df60-48d8-11e8-a5e5-263fa1a58213",
    "product_uuid": "7fc85970-a2d0-11e2-9cd0-1231430706c1",
    "from": "2025-01-15T14:00:00Z",
    "to": "2025-01-15T14:30:00Z"
  }'

# Response contains participation.customer_uuid -> remember it!

Step 3: Finalize Booking

curl -X POST "https://www.timum.de/resources/immobilie-123@is24/create_appointment_with_consumer" \
  -H "Content-Type: application/json" \
  -d '{
    "start": "2025-01-15T14:00:00Z",
    "end": "2025-01-15T14:30:00Z",
    "timeslot_uuid": "6cb6df60-48d8-11e8-a5e5-263fa1a58213",
    "product_uuid": "7fc85970-a2d0-11e2-9cd0-1231430706c1",
    "placeholder_id": "a48df610-483c-11f0-b6e3-72fe2304273f",
    "email": "interessent@example.com",
    "firstname": "Max",
    "lastname": "Interessent",
    "mobile": "0173 9876543",
    "locale": "de"
  }'

Related Topics