Consumer Booking Flow
Consumer-facing Endpunkte für die Terminbuchung. Diese Endpunkte werden auch vom BookingJS-Widget verwendet und sind für Frontend-Integrationen optimiert.
Keine Authentifizierung erforderlich
Übersicht
Der Standard-Buchungsflow besteht aus drei Schritten:
- Verfügbare Termine abrufen - Liste aller buchbaren Slots
- Termin reservieren - 3-Minuten-Hold für ausgewählten Slot
- Buchung abschließen - Termin mit Consumer-Daten finalisieren
| Methode | Endpunkt | Beschreibung |
|---|---|---|
GET | /resources/:ref/upcoming_bookables | Verfügbare Termine abrufen |
POST | /rest/1/resources/:ref/reserve_appointment | Termin reservieren (3 Min) |
POST | /resources/:ref/create_appointment_with_consumer | Buchung finalisieren |
POST | /products/active_products | Aktive Produkte abrufen |
POST | /resources/public_data | Öffentliche Ressourcen-Daten |
OPTIONS | /resources/:ref/upcoming_bookables | CORS Preflight |
1. Verfügbare Termine abrufen
Ruft alle buchbaren Zeitfenster für eine oder mehrere Ressourcen ab. Die Ergebnisse sind nach einem konfigurierbaren Datumsformat gruppiert, um eine zweistufige UI (z.B. Monatsansicht → Tagesliste) einfach zu ermöglichen.
GET /resources/{ref}/upcoming_bookablesPfad-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
ref | string | Ressourcen-Referenz oder UUID. Formate:
|
Query-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
groupFormat | string | Nein | Joda-Time-Format für die Gruppierung. Alle Bookables mit gleichem Wert landen in einer Gruppe. Standard: yyyy-MM-dd. Beispiele: MM-yyyy (monatlich), MMMM (Monatsname) |
timeFormat | string | Nein | Format für formattedStart/formattedEnd. Standard: yyyy-MM-dd HH:mm |
languageTag | string | Nein | IETF BCP 47 Language Tag für serverseitige Übersetzung (z.B. Monatsnamen). Beispiel: de_DE, fr_FR |
channelKey | string | Nein | Booking-Channel. Standard: RESOURCE_PUBLIC. Siehe Channel Keys |
ref | string | Nein | Zusätzliche Ressourcen-Referenzen. Kann mehrfach angegeben werden, um Bookables für mehrere Ressourcen gleichzeitig zu laden |
prdRef | string | Nein | Produkt-Referenz oder UUID. Filtert auf Bookables, die dieses Produkt unterstützen. Berücksichtigt auch leadTime/followUpTime des Produkts |
Request
curl -X GET "https://www.timum.de/resources/my-resource@myPlatform/upcoming_bookables?groupFormat=MMMM&languageTag=fr_FR"Response
Die Response ist ein Objekt mit dynamischen Keys basierend auf dem groupFormat. Zusätzlich enthält sie ein public_visible Flag.
{
"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-Typen
| kind | Bedeutung | Besonderheit |
|---|---|---|
models.Bookable | Slot aus einer Verfügbarkeit (Timeslot) | Wird bei der ersten Buchung zu einem LotAppointment. Verwenden Sie timeslot_uuid für Reserve/Create |
models.LotAppointment | Bestehender Gruppen-Termin mit Restkapazität | Bereits erstellter Termin. Verwenden Sie appointment_uuidfür Reserve/Create |
Bookable vs LotAppointment
models.Bookable ist ein potenzieller Slot aus einer Verfügbarkeit. Sobald der erste Consumer bucht, wird daraus ein models.LotAppointmentmit einer neuen appointment_uuid. Bei weiteren Buchungen desselben Slots müssen Sie diese neue UUID verwenden!Response-Felder
| Feld | Typ | Beschreibung |
|---|---|---|
start / end | string | ISO-8601 Zeitstempel mit Timezone |
formattedStart / formattedEnd | string | Nach timeFormat formatierte Zeit |
timeslot_uuid | string | UUID der zugrundeliegenden Verfügbarkeit |
appointment_uuid | string? | UUID des Termins (nur bei LotAppointment) |
product_uuid | string? | UUID des Produkts oder null |
resource_uuid | string | UUID der Ressource |
capacity | number | Gesamtkapazität des Slots |
capacity_left | number | Verbleibende freie Plätze |
contact_channel | object? | Kontakt-Kanal mit type und value |
products | array | Liste der verfügbaren Produkte für diesen Slot |
kind | string | models.Bookable oder models.LotAppointment |
Status Codes
| Code | Bedeutung |
|---|---|
200 | Erfolgreich, Bookables zurückgegeben |
204 | Keine Bookables verfügbar (leere Response) |
2. Termin reservieren
Reserviert einen Termin temporär für 3 Minuten. Während dieser Zeit kann der Slot nur vom reservierenden Customer gebucht werden. Dies verhindert Doppelbuchungen während der Formular-Eingabe.
POST /rest/1/resources/{ref}/reserve_appointmentImmer vor dem Buchen aufrufen
create_appointment_with_consumer verwenden! Auch nach Ablauf der 3 Minuten können Sie die Buchung noch abschließen - aber wenn ein anderer Customer schneller war, schlägt sie fehl.Query-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
ref | string | Nein | Ressourcen- oder Channel-Referenz |
channelKey | string | Nein | Booking-Channel. Standard: RESOURCE_PUBLIC |
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
timeslot_uuid | string | Bedingt* | UUID des Timeslots (Verfügbarkeit). Verwenden bei models.Bookable. Wendet Standard-Einstellungen der Verfügbarkeit auf den neuen Termin an |
appointment_uuid | string | Bedingt* | UUID des bestehenden Termins. Pflicht bei models.LotAppointment |
product_uuid | string | Ja | UUID des zu buchenden Produkts |
from | string | Ja | Startzeit des Bookables (ISO-8601, UTC) |
to | string | Ja | Endzeit des Bookables (ISO-8601, UTC) |
* Bei models.Bookable senden Sie timeslot_uuid. Bei models.LotAppointment ist appointment_uuid Pflicht.
Request
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
{
"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"
}
]
}
]
}customer_uuid speichern
participation.customer_uuid aus der Response! Sie benötigen diesen Wert als placeholder_id für dencreate_appointment_with_consumer Aufruf.Reservierungs-Verhalten
- Die Reservierung gilt für 3 Minuten
- Der
stateistRESERVED - Nach Ablauf wird die Reservierung automatisch gelöscht
- Die
capacity_leftwird während der Reservierung reduziert - Auch nach Timeout können Sie noch buchen - aber ohne Schutz vor Doppelbuchung
3. Buchung finalisieren
Schließt die Buchung mit den Consumer-Daten ab. Wenn ein Nutzer mit der angegebenen Email oder Telefonnummer bereits existiert, wird der Termin dessen Account zugeordnet. Andernfalls wird ein neuer Account erstellt.
POST /resources/{ref}/create_appointment_with_consumerQuery-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
timeFormat | string | Nein | Format für Zeitangaben in der Response |
Request Body
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
start | string | Ja | Startzeit (ISO-8601) |
end | string | Ja | Endzeit (ISO-8601) |
timeslot_uuid | string | Ja | UUID des Timeslots oder Termins |
product_uuid | string | Nein | UUID des Produkts |
placeholder_id | string | Nein* | participation.customer_uuid aus der Reserve-Response. Identifiziert die Reservierung |
email | string | Ja | Email des Consumers |
firstname | string | Ja | Vorname des Consumers |
lastname | string | Ja | Nachname des Consumers |
mobile | string | Nein | Mobilnummer des Consumers |
message | string | Nein | Optionale Nachricht (max. 1024 Zeichen) |
locale | string | Nein | Sprachcode (z.B. de, en). Bestimmt die Sprache transaktionaler Emails |
channelKey | string | Nein | Booking-Channel. Standard: RESOURCE_PUBLIC |
* placeholder_id ist technisch optional, aber Sie sollten ihn immer senden, um sicherzustellen, dass die Reservierung Ihres Nutzers verwendet wird.
Request
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 (Erfolg)
{
"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
cancelLink. Dieser signierte Link ermöglicht es dem Consumer, seinen Termin selbständig zu stornieren. Sie können diesen Link in Ihrer Bestätigungs-Email verwenden.Response (Fehler)
{
"api-info": { "version": "1" },
"errors": [
{
"errorCode": "201",
"message": "Das überlappt mit einem anderen Termin."
}
]
}Algorithmus-Details
- Wenn ein Nutzer mit der Email oder Mobilnummer bereits existiert, wird der Termin dessen Account zugeordnet
- Fehlende Attribute (firstname, lastname, mobile) werden beim bestehenden Nutzer ergänzt, aber nicht überschrieben
- Die Sprache des neuen Nutzers wird vom CRM-Actor übernommen (oder via
localeParameter) - Bei Gruppentterminen: Erste Buchung erstellt den Termin, weitere erhöhen die Teilnehmerzahl
Status Codes
| Code | Bedeutung |
|---|---|
201 | Termin erfolgreich erstellt |
400 | Pflichtfeld fehlt oder ungültig |
412 | Slot bereits gebucht (errorCode 201) |
Troubleshooting
| Problem | Ursache | Lösung |
|---|---|---|
| "Das überlappt mit einem anderen Termin" (errorCode 201) | Slot auf einer Verfügbarkeit bereits gebucht. Erste Buchung erzeugt neuen Termin mit neuer UUID | Verwenden Sie die neue timeslot_uuid aus der ersten Buchungs-Response für weitere Buchungen |
| "Email fehlt" obwohl sie im Body ist | Redirect-Problem wegen fehlendem www. | Stellen Sie sicher, dass Sie https://www.timum.deverwenden (mit www.) |
| 301 Redirect ohne Response | Fehlendes www. in der URL | Verwenden Sie immer https://www.timum.de |
| AppointmentAlreadyBookedException | Der Consumer nimmt bereits an diesem Termin teil | Ein Nutzer kann nicht zweimal am selben Termin teilnehmen. Prüfen Sie auf Duplikate |
4. Aktive Produkte abrufen
Ruft alle aktiven/freigeschalteten Produkte einer Ressource ab. Die Ergebnisliste kann je nach Channel-Einstellungen gefiltert sein.
POST /products/active_productsQuery-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
ref | string | Bedingt* | Ressourcen- oder Channel-Referenz. Kann mehrfach angegeben werden |
tslRefs | string | Bedingt* | Termin- oder Verfügbarkeits-Referenz. Kann mehrfach angegeben werden |
channelKey | string | Nein | Booking-Channel. Standard: RESOURCE_PUBLIC |
* Mindestens ref oder tslRefs muss angegeben werden.
Request
curl -X POST "https://www.timum.de/products/active_products?ref=my-resource@myPlatform&channelKey=RESOURCE_PUBLIC"Response
{
"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-Felder
| Feld | Typ | Beschreibung |
|---|---|---|
uuid | string | Eindeutige Produkt-ID |
name | string | Anzeigename des Produkts |
description | string | Produktbeschreibung (für Kunden-Hinweise) |
minDuration | number? | Minimale Dauer in Minuten |
maxDuration | number? | Maximale Dauer in Minuten |
leadTimeMinutes | number? | Vorlaufzeit (Anfahrt/Vorbereitung) in Minuten |
followUpTimeMinutes | number? | Nachlaufzeit (Rückfahrt/Nachbereitung) in Minuten |
exclusive | boolean | Ob das Produkt exklusiv ist (nur für bestimmte Channels) |
5. Öffentliche Daten abrufen
Ruft öffentliche Informationen über Provider, Ressource, Channel-Einstellungen und Kontaktperson ab. Nützlich für die Darstellung von Booking-Widgets.
POST /resources/public_dataQuery-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
ref | string | Bedingt* | Ressourcen- oder Channel-Referenz. Kann mehrfach angegeben werden |
tslRefs | string | Bedingt* | Termin- oder Verfügbarkeits-Referenz. Kann mehrfach angegeben werden |
channelKey | string | Nein | Booking-Channel. Standard: RESOURCE_PUBLIC |
* Mindestens ref oder tslRefs muss angegeben werden.
Request
curl -X POST "https://www.timum.de/resources/public_data?ref=my-resource@myPlatform&channelKey=RESOURCE_PUBLIC"Response
{
"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-Struktur
contact
| Feld | Beschreibung |
|---|---|
name | Name der Kontaktperson (aus Contact Profile) |
email | Öffentliche Email-Adresse |
mobile | Mobilnummer |
phone | Festnetznummer |
resource
| Feld | Beschreibung |
|---|---|
uuid | Eindeutige Ressourcen-ID |
name | Öffentlicher Name der Ressource |
description | Beschreibung der Ressource |
url | Externe URL (z.B. Link zum Exposé) |
imgUrl | Bild-URL der Ressource |
provider
| Feld | Beschreibung |
|---|---|
name | Kalender-/Firmennamen |
description | Beschreibung des Providers |
isThemingAllowed | Ob Custom Theming erlaubt ist |
isLocalisationAllowed | Ob Custom Lokalisierung erlaubt ist |
areCustomFieldsAllowed | Ob Custom Fields erlaubt sind |
channel
| Feld | Beschreibung |
|---|---|
bookingProcess | IMMEDIATE = Direktbuchung,REQUESTED = Terminanfrage |
6. CORS Preflight
Browser senden automatisch OPTIONS-Requests vor Cross-Origin-Anfragen. timum beantwortet diese für alle Consumer Booking Endpunkte automatisch.
OPTIONS /resources/{ref}/upcoming_bookablesResponse 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: 36Automatische CORS-Unterstützung
Channel Keys
timum unterstützt 4 verschiedene Booking-Channels. Jeder Channel hat eigene Einstellungen für Sichtbarkeit, Buchungsprozess und Produktfilter.
| channelKey | Name (UI) | Verwendung |
|---|---|---|
RESOURCE_PUBLIC | Öffentlicher Buchungs-Link | Standard-Channel. Öffentlich publizierbar |
RESOURCE_EXCLUSIVE | Exklusiver Buchungs-Zugang | Für akzeptierte Kunden (Adressbuch) |
RESOURCE_REFERENCE | Eingebettete Buchungskalender | Für automatisch generierte Embeds (z.B. Immobilienportale) |
CALENDAR_PUBLIC | Website-Plugin & Gesamtkalender | Für Website-Plugins mit allen Ressourcen |
Die Channel-Einstellungen können im timum-Frontend unterRessource → Terminbuchung freigeben konfiguriert werden.
Buchungsprozesse
| Prozess | Beschreibung |
|---|---|
IMMEDIATE | Direkte Buchung. Der Termin wird sofort bestätigt. Consumer erhält Bestätigung, Provider erhält Benachrichtigung |
REQUESTED | Terminanfrage. Der Termin muss vom Provider bestätigt werden. Consumer erhält "Anfrage eingegangen", Provider erhält Anfrage zur Bestätigung |
Vollständiger Buchungsflow
Hier ist der komplette Ablauf für eine Terminbuchung:
Schritt 1: Bookables laden
curl "https://www.timum.de/resources/immobilie-123@is24/upcoming_bookables?groupFormat=yyyy-MM-dd&prdRef=besichtigung-30min@is24"Schritt 2: Slot reservieren
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 enthält participation.customer_uuid -> merken!Schritt 3: Buchung finalisieren
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"
}'Verwandte Themen
- API-Übersicht - Authentifizierung, Base URL, Fehlerformat
- Configure Offerings - Ressourcen und Produkte erstellen
- Scheduling - Verfügbarkeiten und Termine verwalten
- Widget-Integration - BookingJS Widget einbinden
War diese Seite hilfreich?
