Flusso di prenotazione
Endpoint orientati al consumer per la prenotazione di appuntamenti. Questi endpoint vengono utilizzati anche dal widget BookingJS e sono ottimizzati per le integrazioni frontend.
Nessuna autenticazione richiesta
Panoramica
Il flusso di prenotazione standard è composto da tre passaggi:
- Recuperare gli appuntamenti disponibili - elenco di tutti gli slot prenotabili
- Prenotare l'appuntamento - blocco di 3 minuti per lo slot selezionato
- Completare la prenotazione - finalizzare l'appuntamento con i dati del consumer
| Metodo | Endpoint | Descrizione |
|---|---|---|
GET | /resources/:ref/upcoming_bookables | Recuperare gli appuntamenti disponibili |
POST | /rest/1/resources/:ref/reserve_appointment | Prenotare l'appuntamento (3 min) |
POST | /resources/:ref/create_appointment_with_consumer | Completare la prenotazione |
POST | /products/active_products | Recuperare i prodotti attivi |
POST | /resources/public_data | Dati pubblici delle risorse |
OPTIONS | /resources/:ref/upcoming_bookables | Preflight CORS |
1. Recuperare gli appuntamenti disponibili
Recupera tutte le fasce orarie prenotabili per una o più risorse. I risultati sono raggruppati secondo un formato di data configurabile, per facilitare una UI a due livelli (ad es. vista mensile → elenco giornaliero).
GET /resources/{ref}/upcoming_bookables
Parametri del percorso
| Parametro | Tipo | Descrizione |
|---|---|---|
ref | string | Riferimento risorsa o UUID. Formati: resourceId@providerUuid@platform - riferimento completo; resourceId@platform - forma breve; uuid - UUID diretto della risorsa |
Parametri della query
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
groupFormat | string | No | Formato Joda-Time per il raggruppamento. Tutti i bookable con lo stesso valore finiscono nello stesso gruppo. Predefinito: yyyy-MM-dd. Esempi: MM-yyyy (mensile), MMMM (nome del mese) |
timeFormat | string | No | Formato per formattedStart/formattedEnd. Predefinito: yyyy-MM-dd HH:mm |
languageTag | string | No | Language tag IETF BCP 47 per la traduzione lato server (ad es. nomi dei mesi). Esempio: de_DE, fr_FR |
channelKey | string | No | Canale di prenotazione. Predefinito: RESOURCE_PUBLIC. Vedere Channel Keys |
ref | string | No | Riferimenti risorsa aggiuntivi. Può essere specificato più volte per caricare i bookable di più risorse contemporaneamente |
prdRef | string | No | Riferimento prodotto o UUID. Filtra i bookable che supportano questo prodotto. Tiene conto anche di leadTime/followUpTime del prodotto |
Request
curl -X GET "https://www.timum.de/resources/my-resource@myPlatform/upcoming_bookables?groupFormat=MMMM&languageTag=fr_FR"
Response
La response è un oggetto con chiavi dinamiche basate su groupFormat. Contiene inoltre un flag public_visible.
{
"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
}
Tipi di Bookable
| kind | Significato | Particolarità |
|---|---|---|
models.Bookable | Slot proveniente da una disponibilità (timeslot) | Diventa un LotAppointment con la prima prenotazione. Usare timeslot_uuid per reserve/create |
models.LotAppointment | Appuntamento di gruppo esistente con capacità residua | Appuntamento già creato. Usare appointment_uuid per reserve/create |
Bookable vs LotAppointment
models.Bookable è uno slot potenziale proveniente da una disponibilità. Non appena il primo consumer prenota, diventa un models.LotAppointment con un nuovo appointment_uuid. Per ulteriori prenotazioni dello stesso slot, è necessario usare questo nuovo UUID!Campi della response
| Campo | Tipo | Descrizione |
|---|---|---|
start / end | string | Timestamp ISO 8601 con fuso orario |
formattedStart / formattedEnd | string | Orario formattato secondo timeFormat |
timeslot_uuid | string | UUID della disponibilità sottostante |
appointment_uuid | string? | UUID dell'appuntamento (solo per LotAppointment) |
product_uuid | string? | UUID del prodotto, o null |
resource_uuid | string | UUID della risorsa |
capacity | number | Capacità totale dello slot |
capacity_left | number | Posti liberi residui |
contact_channel | object? | Canale di contatto con type e value |
products | array | Elenco dei prodotti disponibili per questo slot |
kind | string | models.Bookable o models.LotAppointment |
Codici di stato
| Codice | Significato |
|---|---|
200 | Riuscito, bookable restituiti |
204 | Nessun bookable disponibile (response vuota) |
2. Prenotare l'appuntamento
Prenota temporaneamente un appuntamento per 3 minuti. Durante questo periodo, lo slot può essere prenotato solo dal customer che ha effettuato la prenotazione. Questo evita doppie prenotazioni durante la compilazione del modulo.
POST /rest/1/resources/{ref}/reserve_appointment
Richiamare sempre prima della prenotazione
create_appointment_with_consumer! Anche dopo la scadenza dei 3 minuti è ancora possibile completare la prenotazione - ma se un altro customer è stato più veloce, l'operazione fallisce.Parametri della query
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
ref | string | No | Riferimento risorsa o canale |
channelKey | string | No | Canale di prenotazione. Predefinito: RESOURCE_PUBLIC |
Request Body
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
timeslot_uuid | string | Condizionale* | UUID del timeslot (disponibilità). Da usare per models.Bookable. Applica le impostazioni predefinite della disponibilità al nuovo appuntamento |
appointment_uuid | string | Condizionale* | UUID dell'appuntamento esistente. Obbligatorio per models.LotAppointment |
product_uuid | string | Sì | UUID del prodotto da prenotare |
from | string | Sì | Orario di inizio del bookable (ISO 8601, UTC) |
to | string | Sì | Orario di fine del bookable (ISO 8601, UTC) |
* Per models.Bookable inviare timeslot_uuid. Per models.LotAppointment, appointment_uuid è obbligatorio.
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"
}
]
}
]
}
Salvare customer_uuid
participation.customer_uuid dalla response! Questo valore serve come placeholder_id per la chiamata a create_appointment_with_consumer.Comportamento della prenotazione
- La prenotazione è valida per 3 minuti
- Lo
stateèRESERVED - Alla scadenza, la prenotazione viene eliminata automaticamente
capacity_leftviene ridotto durante la prenotazione- È possibile prenotare anche dopo il timeout - ma senza protezione dalla doppia prenotazione
3. Completare la prenotazione
Conclude la prenotazione con i dati del consumer. Se esiste già un utente con l'email o il numero di telefono indicati, l'appuntamento viene associato a quell'account. In caso contrario, viene creato un nuovo account.
POST /resources/{ref}/create_appointment_with_consumer
Parametri della query
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
timeFormat | string | No | Formato per gli orari nella response |
Request Body
| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
start | string | Sì | Orario di inizio (ISO 8601) |
end | string | Sì | Orario di fine (ISO 8601) |
timeslot_uuid | string | Sì | UUID del timeslot o dell'appuntamento |
product_uuid | string | No | UUID del prodotto |
placeholder_id | string | No* | participation.customer_uuid dalla response di reserve. Identifica la prenotazione |
email | string | Sì | Email del consumer |
firstname | string | Sì | Nome del consumer |
lastname | string | Sì | Cognome del consumer |
mobile | string | No | Numero di cellulare del consumer |
message | string | No | Messaggio facoltativo (max. 1024 caratteri) |
locale | string | No | Codice lingua (ad es. de, en). Determina la lingua delle email transazionali |
channelKey | string | No | Canale di prenotazione. Predefinito: RESOURCE_PUBLIC |
* placeholder_id è tecnicamente facoltativo, ma dovrebbe essere sempre inviato per garantire che venga usata la prenotazione del proprio utente.
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 (Successo)
{
"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. Questo link firmato consente al consumer di annullare autonomamente il proprio appuntamento. Può usare questo link nella sua email di conferma.Response (Errore)
{
"api-info": { "version": "1" },
"errors": [
{
"errorCode": "201",
"message": "Das überlappt mit einem anderen Termin."
}
]
}
Dettagli dell'algoritmo
- Se esiste già un utente con l'email o il numero di cellulare, l'appuntamento viene associato a quell'account
- Gli attributi mancanti (firstname, lastname, mobile) vengono aggiunti all'utente esistente, ma non sovrascritti
- La lingua del nuovo utente viene ripresa dall'actor CRM (oppure tramite il parametro
locale) - Per gli appuntamenti di gruppo: la prima prenotazione crea l'appuntamento, le successive aumentano il numero di partecipanti
Codici di stato
| Codice | Significato |
|---|---|
201 | Appuntamento creato con successo |
400 | Campo obbligatorio mancante o non valido |
412 | Slot già prenotato (errorCode 201) |
Risoluzione dei problemi
| Problema | Causa | Soluzione |
|---|---|---|
| "Das überlappt mit einem anderen Termin" (errorCode 201) | Slot di una disponibilità già prenotato. La prima prenotazione genera un nuovo appuntamento con un nuovo UUID | Usare il nuovo timeslot_uuid dalla prima response di prenotazione per le prenotazioni successive |
| "Email mancante" anche se è presente nel body | Problema di redirect dovuto alla mancanza di www. | Assicurarsi di usare https://www.timum.de (con www.) |
| Redirect 301 senza response | www. mancante nell'URL | Usare sempre https://www.timum.de |
| AppointmentAlreadyBookedException | Il consumer partecipa già a questo appuntamento | Un utente non può partecipare due volte allo stesso appuntamento. Verificare la presenza di duplicati |
4. Recuperare i prodotti attivi
Recupera tutti i prodotti attivi/abilitati di una risorsa. L'elenco dei risultati può essere filtrato in base alle impostazioni del canale.
POST /products/active_products
Parametri della query
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
ref | string | Condizionale* | Riferimento risorsa o canale. Può essere specificato più volte |
tslRefs | string | Condizionale* | Riferimento appuntamento o disponibilità. Può essere specificato più volte |
channelKey | string | No | Canale di prenotazione. Predefinito: RESOURCE_PUBLIC |
* Deve essere specificato almeno ref o tslRefs.
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
}
]
}
Campi della response
| Campo | Tipo | Descrizione |
|---|---|---|
uuid | string | ID univoco del prodotto |
name | string | Nome visualizzato del prodotto |
description | string | Descrizione del prodotto (per note ai clienti) |
minDuration | number? | Durata minima in minuti |
maxDuration | number? | Durata massima in minuti |
leadTimeMinutes | number? | Tempo di anticipo (viaggio/preparazione) in minuti |
followUpTimeMinutes | number? | Tempo successivo (ritorno/chiusura) in minuti |
exclusive | boolean | Indica se il prodotto è esclusivo (solo per determinati canali) |
5. Recuperare i dati pubblici
Recupera informazioni pubbliche su provider, risorsa, impostazioni del canale e persona di contatto. Utile per la visualizzazione dei widget di prenotazione.
POST /resources/public_data
Parametri della query
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
ref | string | Condizionale* | Riferimento risorsa o canale. Può essere specificato più volte |
tslRefs | string | Condizionale* | Riferimento appuntamento o disponibilità. Può essere specificato più volte |
channelKey | string | No | Canale di prenotazione. Predefinito: RESOURCE_PUBLIC |
* Deve essere specificato almeno ref o tslRefs.
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"
}
}
Struttura della response
contact
| Campo | Descrizione |
|---|---|
name | Nome della persona di contatto (dal contact profile) |
email | Indirizzo email pubblico |
mobile | Numero di cellulare |
phone | Numero di telefono fisso |
resource
| Campo | Descrizione |
|---|---|
uuid | ID univoco della risorsa |
name | Nome pubblico della risorsa |
description | Descrizione della risorsa |
url | URL esterno (ad es. link all'annuncio immobiliare) |
imgUrl | URL dell'immagine della risorsa |
provider
| Campo | Descrizione |
|---|---|
name | Nome calendario/azienda |
description | Descrizione del provider |
isThemingAllowed | Indica se è consentito il theming personalizzato |
isLocalisationAllowed | Indica se è consentita la localizzazione personalizzata |
areCustomFieldsAllowed | Indica se sono consentiti i campi personalizzati |
channel
| Campo | Descrizione |
|---|---|
bookingProcess | IMMEDIATE = prenotazione diretta, REQUESTED = richiesta di appuntamento |
6. Preflight CORS
I browser inviano automaticamente richieste OPTIONS prima delle richieste cross-origin. timum risponde automaticamente a queste richieste per tutti gli endpoint di prenotazione per i consumer.
OPTIONS /resources/{ref}/upcoming_bookables
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
Supporto CORS automatico
Channel Keys
timum supporta 4 canali di prenotazione diversi. Ogni canale ha impostazioni proprie per visibilità, processo di prenotazione e filtro dei prodotti.
| channelKey | Nome (UI) | Utilizzo |
|---|---|---|
RESOURCE_PUBLIC | Link di prenotazione pubblico | Canale predefinito. Può essere pubblicato pubblicamente |
RESOURCE_EXCLUSIVE | Accesso di prenotazione esclusivo | Per clienti accettati (rubrica) |
RESOURCE_REFERENCE | Calendario di prenotazione incorporato | Per embed generati automaticamente (ad es. portali immobiliari) |
CALENDAR_PUBLIC | Plugin per sito web e calendario complessivo | Per plugin per sito web con tutte le risorse |
Le impostazioni del canale possono essere configurate nel frontend timum in Risorsa → Abilita prenotazione appuntamenti.
Processi di prenotazione
| Processo | Descrizione |
|---|---|
IMMEDIATE | Prenotazione diretta. L'appuntamento viene confermato immediatamente. Il consumer riceve una conferma, il provider riceve una notifica |
REQUESTED | Richiesta di appuntamento. L'appuntamento deve essere confermato dal provider. Il consumer riceve "Richiesta ricevuta", il provider riceve la richiesta da confermare |
Flusso di prenotazione completo
Ecco il flusso completo per la prenotazione di un appuntamento:
Passaggio 1: caricare i bookable
curl "https://www.timum.de/resources/immobilie-123@is24/upcoming_bookables?groupFormat=yyyy-MM-dd&prdRef=besichtigung-30min@is24"
Passaggio 2: prenotare lo 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"
}'
# La response contiene participation.customer_uuid -> da ricordare!
Passaggio 3: completare la prenotazione
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"
}'
Argomenti correlati
- Panoramica API - Autenticazione, URL base, formato degli errori
- Configure Offerings - Creare risorse e prodotti
- Scheduling - Gestire disponibilità e appuntamenti
- Integrazione del widget - Integrare il widget BookingJS
