Flujo de reserva

Endpoints orientados al consumidor para la reserva de citas. Estos endpoints también los utiliza el widget BookingJS y están optimizados para integraciones de frontend.

No se requiere autenticación

Los endpoints de reserva para consumidores no requieren una clave de API. Son de acceso público, ya que están pensados para consumidores finales. El control de acceso se realiza mediante la configuración de canal y las referencias de recurso.

Resumen

El flujo de reserva estándar consta de tres pasos:

  1. Obtener citas disponibles - lista de todos los slots reservables
  2. Reservar cita - bloqueo de 3 minutos para el slot seleccionado
  3. Completar la reserva - finalizar la cita con los datos del consumidor
MétodoEndpointDescripción
GET/resources/:ref/upcoming_bookablesObtener citas disponibles
POST/rest/1/resources/:ref/reserve_appointmentReservar cita (3 min)
POST/resources/:ref/create_appointment_with_consumerCompletar la reserva
POST/products/active_productsObtener productos activos
POST/resources/public_dataDatos públicos de recursos
OPTIONS/resources/:ref/upcoming_bookablesPreflight CORS

1. Obtener citas disponibles

Obtiene todos los slots reservables para uno o varios recursos. Los resultados se agrupan según un formato de fecha configurable, para facilitar una UI en dos niveles (p. ej. vista mensual → lista diaria).

Endpoint
GET /resources/{ref}/upcoming_bookables

Parámetros de ruta

ParámetroTipoDescripción
refstringReferencia de recurso o UUID. Formatos: resourceId@providerUuid@platform - referencia completa; resourceId@platform - forma corta; uuid - UUID directo del recurso

Parámetros de consulta

ParámetroTipoObligatorioDescripción
groupFormatstringNoFormato Joda-Time para la agrupación. Todos los bookables con el mismo valor terminan en un mismo grupo. Por defecto: yyyy-MM-dd. Ejemplos: MM-yyyy (mensual), MMMM (nombre del mes)
timeFormatstringNoFormato para formattedStart/formattedEnd. Por defecto: yyyy-MM-dd HH:mm
languageTagstringNoEtiqueta de idioma IETF BCP 47 para la traducción del lado del servidor (p. ej. nombres de meses). Ejemplo: de_DE, fr_FR
channelKeystringNoCanal de reserva. Por defecto: RESOURCE_PUBLIC. Consulte Channel Keys
refstringNoReferencias de recurso adicionales. Puede especificarse varias veces para cargar bookables de varios recursos a la vez
prdRefstringNoReferencia de producto o UUID. Filtra los bookables que admiten este producto. También tiene en cuenta el leadTime/followUpTime del producto

Request

Ejemplo: agrupación mensual en francés
curl -X GET "https://www.timum.de/resources/my-resource@myPlatform/upcoming_bookables?groupFormat=MMMM&languageTag=fr_FR"

Response

La respuesta es un objeto con claves dinámicas basadas en groupFormat. Además, incluye un indicador public_visible.

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
}

Tipos de Bookable

kindSignificadoParticularidad
models.BookableSlot de una disponibilidad (timeslot)Se convierte en un LotAppointment con la primera reserva. Use timeslot_uuid para reserve/create
models.LotAppointmentCita de grupo existente con capacidad restanteCita ya creada. Use appointment_uuid para reserve/create

Bookable vs LotAppointment

Un models.Bookable es un slot potencial de una disponibilidad. En cuanto el primer consumidor reserva, se convierte en un models.LotAppointment con un nuevo appointment_uuid. Para reservas posteriores del mismo slot, debe usar este nuevo UUID.

Campos de la respuesta

CampoTipoDescripción
start / endstringMarca de tiempo ISO 8601 con zona horaria
formattedStart / formattedEndstringHora formateada según timeFormat
timeslot_uuidstringUUID de la disponibilidad subyacente
appointment_uuidstring?UUID de la cita (solo para LotAppointment)
product_uuidstring?UUID del producto, o null
resource_uuidstringUUID del recurso
capacitynumberCapacidad total del slot
capacity_leftnumberPlazas restantes
contact_channelobject?Canal de contacto con type y value
productsarrayLista de productos disponibles para este slot
kindstringmodels.Bookable o models.LotAppointment

Códigos de estado

CódigoSignificado
200Correcto, bookables devueltos
204No hay bookables disponibles (respuesta vacía)

2. Reservar cita

Reserva temporalmente una cita durante 3 minutos. Durante ese tiempo, el slot solo puede reservarlo el cliente que hizo la reserva. Esto evita reservas dobles mientras se rellena el formulario.

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

Llame siempre antes de reservar

Llame siempre a este endpoint antes de usar create_appointment_with_consumer. Incluso después de expirar los 3 minutos, puede completar la reserva - pero si otro cliente fue más rápido, fallará.

Parámetros de consulta

ParámetroTipoObligatorioDescripción
refstringNoReferencia de recurso o de canal
channelKeystringNoCanal de reserva. Por defecto: RESOURCE_PUBLIC

Request Body

CampoTipoObligatorioDescripción
timeslot_uuidstringCondicional*UUID del timeslot (disponibilidad). Usar para models.Bookable. Aplica la configuración por defecto de la disponibilidad a la nueva cita
appointment_uuidstringCondicional*UUID de la cita existente. Obligatorio para models.LotAppointment
product_uuidstringUUID del producto a reservar
fromstringHora de inicio del bookable (ISO 8601, UTC)
tostringHora de fin del bookable (ISO 8601, UTC)

* Para models.Bookable, envíe timeslot_uuid. Para models.LotAppointment, appointment_uuid es obligatorio.

Request

Reservar cita
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"
        }
      ]
    }
  ]
}

Guardar customer_uuid

¡Guarde participation.customer_uuid de la respuesta! Necesitará este valor como placeholder_id para la llamada a create_appointment_with_consumer.

Comportamiento de la reserva

  • La reserva es válida durante 3 minutos
  • El state es RESERVED
  • Al expirar, la reserva se elimina automáticamente
  • capacity_left se reduce mientras dura la reserva
  • Puede reservar incluso después del tiempo de espera - pero sin protección frente a reservas dobles

3. Completar la reserva

Completa la reserva con los datos del consumidor. Si ya existe un usuario con el email o número de teléfono indicado, la cita se asigna a esa cuenta. En caso contrario, se crea una nueva cuenta.

Endpoint
POST /resources/{ref}/create_appointment_with_consumer

Parámetros de consulta

ParámetroTipoObligatorioDescripción
timeFormatstringNoFormato para los valores de tiempo en la respuesta

Request Body

CampoTipoObligatorioDescripción
startstringHora de inicio (ISO 8601)
endstringHora de fin (ISO 8601)
timeslot_uuidstringUUID del timeslot o de la cita
product_uuidstringNoUUID del producto
placeholder_idstringNo*participation.customer_uuid de la respuesta de reserva. Identifica la reserva
emailstringEmail del consumidor
firstnamestringNombre del consumidor
lastnamestringApellido del consumidor
mobilestringNoNúmero de móvil del consumidor
messagestringNoMensaje opcional (máx. 1024 caracteres)
localestringNoCódigo de idioma (p. ej. de, en). Determina el idioma de los emails transaccionales
channelKeystringNoCanal de reserva. Por defecto: RESOURCE_PUBLIC

* placeholder_id es técnicamente opcional, pero debería enviarlo siempre para garantizar que se use la reserva de su usuario.

Request

Completar la reserva
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 (Éxito)

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

La respuesta incluye un cancelLink. Este enlace firmado permite al consumidor cancelar su cita de forma autónoma. Puede usar este enlace en su email de confirmación.

Response (Error)

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

Detalles del algoritmo

  • Si ya existe un usuario con el email o el número de móvil, la cita se asigna a esa cuenta
  • Los atributos que falten (firstname, lastname, mobile) se completan en el usuario existente, pero nunca se sobrescriben
  • El idioma del nuevo usuario se toma del actor del CRM (o mediante el parámetro locale)
  • En citas de grupo: la primera reserva crea la cita, las siguientes aumentan el número de participantes

Códigos de estado

CódigoSignificado
201Cita creada correctamente
400Falta un campo obligatorio o no es válido
412Slot ya reservado (errorCode 201)

Solución de problemas

ProblemaCausaSolución
"Das überlappt mit einem anderen Termin" (errorCode 201)Slot de una disponibilidad ya reservado. La primera reserva genera una nueva cita con un nuevo UUIDUse el nuevo timeslot_uuid de la primera respuesta de reserva para reservas posteriores
"Falta el email" aunque está en el bodyProblema de redirección por falta de www.Asegúrese de usar https://www.timum.de (con www.)
Redirección 301 sin respuestaFalta www. en la URLUse siempre https://www.timum.de
AppointmentAlreadyBookedExceptionEl consumidor ya participa en esta citaUn usuario no puede participar dos veces en la misma cita. Compruebe si hay duplicados

4. Obtener productos activos

Obtiene todos los productos activos/habilitados de un recurso. La lista de resultados puede estar filtrada según la configuración de canal.

Endpoint
POST /products/active_products

Parámetros de consulta

ParámetroTipoObligatorioDescripción
refstringCondicional*Referencia de recurso o de canal. Puede especificarse varias veces
tslRefsstringCondicional*Referencia de cita o de disponibilidad. Puede especificarse varias veces
channelKeystringNoCanal de reserva. Por defecto: RESOURCE_PUBLIC

* Debe especificarse al menos ref o tslRefs.

Request

Obtener productos
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
    }
  ]
}

Campos de la respuesta

CampoTipoDescripción
uuidstringID único del producto
namestringNombre para mostrar del producto
descriptionstringDescripción del producto (para notas de cliente)
minDurationnumber?Duración mínima en minutos
maxDurationnumber?Duración máxima en minutos
leadTimeMinutesnumber?Tiempo de antelación (desplazamiento/preparación) en minutos
followUpTimeMinutesnumber?Tiempo posterior (regreso/cierre) en minutos
exclusivebooleanIndica si el producto es exclusivo (solo para determinados canales)

5. Obtener datos públicos

Obtiene información pública sobre el provider, el recurso, la configuración de canal y la persona de contacto. Útil para mostrar los widgets de reserva.

Endpoint
POST /resources/public_data

Parámetros de consulta

ParámetroTipoObligatorioDescripción
refstringCondicional*Referencia de recurso o de canal. Puede especificarse varias veces
tslRefsstringCondicional*Referencia de cita o de disponibilidad. Puede especificarse varias veces
channelKeystringNoCanal de reserva. Por defecto: RESOURCE_PUBLIC

* Debe especificarse al menos ref o tslRefs.

Request

Obtener datos públicos
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"
  }
}

Estructura de la respuesta

contact

CampoDescripción
nameNombre de la persona de contacto (del contact profile)
emailDirección de email pública
mobileNúmero de móvil
phoneNúmero de teléfono fijo

resource

CampoDescripción
uuidID único del recurso
nameNombre público del recurso
descriptionDescripción del recurso
urlURL externa (p. ej. enlace al anuncio inmobiliario)
imgUrlURL de la imagen del recurso

provider

CampoDescripción
nameNombre del calendario/empresa
descriptionDescripción del provider
isThemingAllowedIndica si se permite theming personalizado
isLocalisationAllowedIndica si se permite localización personalizada
areCustomFieldsAllowedIndica si se permiten campos personalizados

channel

CampoDescripción
bookingProcessIMMEDIATE = reserva directa, REQUESTED = solicitud de cita

6. Preflight CORS

Los navegadores envían automáticamente solicitudes OPTIONS antes de las solicitudes cross-origin. timum las responde automáticamente para todos los endpoints de reserva para consumidores.

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

Soporte CORS automático

Se aceptan solicitudes cross-origin desde cualquier origen. No necesita configurar nada especial. Los navegadores realizan estas solicitudes preflight automáticamente.

Channel Keys

timum admite 4 canales de reserva diferentes. Cada canal tiene su propia configuración de visibilidad, proceso de reserva y filtrado de productos.

channelKeyNombre (UI)Uso
RESOURCE_PUBLICEnlace de reserva públicoCanal por defecto. Puede publicarse públicamente
RESOURCE_EXCLUSIVEAcceso de reserva exclusivoPara clientes aceptados (libreta de direcciones)
RESOURCE_REFERENCECalendario de reserva incrustadoPara embeds generados automáticamente (p. ej. portales inmobiliarios)
CALENDAR_PUBLICPlugin de sitio web y calendario completoPara plugins de sitio web con todos los recursos

La configuración de canal puede ajustarse en el frontend de timum en Recurso → Habilitar reserva de citas.

Procesos de reserva

ProcesoDescripción
IMMEDIATEReserva directa. La cita se confirma inmediatamente. El consumidor recibe una confirmación, el provider recibe una notificación
REQUESTEDSolicitud de cita. La cita debe ser confirmada por el provider. El consumidor recibe "Solicitud recibida", el provider recibe la solicitud para confirmarla

Flujo de reserva completo

Este es el flujo completo para reservar una cita:

Paso 1: Cargar bookables

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

Paso 2: Reservar el 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 respuesta contiene participation.customer_uuid -> ¡recuérdelo!

Paso 3: Completar la reserva

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"
  }'

Temas relacionados