> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dialtu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agendar citas de calendario

> Crea citas desde un sistema externo: cada campo explícito, sin sorpresas

Usa los endpoints de calendario para agendar citas en tu calendario de Dialtu desde n8n,
Zapier, un formulario web o tu propio backend, y para comprobar cuánto espacio queda antes de
hacerlo:

* **Get bookable capacity per service** — `GET /api/v2/public/calendar/availability`
* **List bookable services** — `GET /api/v2/public/calendar/services`
* **Book an appointment** — `POST /api/v2/public/calendar/events`
* **Listas de espera**: añadir, listar, quitar y resumir entradas bajo `/api/v2/public/calendar/waitlist/`

<Note>
  **Todos los campos de una reserva son obligatorios.** Esta API no tiene valores por defecto:
  nunca elige por ti el servicio, el profesional ni el tipo de cita, nunca deriva la hora de fin
  de una duración y nunca envía una notificación que no hayas configurado. Si un valor no
  coincide con algo de tu cuenta, la solicitud se rechaza y el error lista lo que sí se habría
  aceptado.
</Note>

## Conceptos

Una cita se compone de cuatro cosas, y **tú aportas las cuatro**.

| Cosa             | Qué es                                                                                                                                                   | Cómo la envías                              |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| **Cliente**      | El paciente o cliente. **Se busca por teléfono**; se crea automáticamente la primera vez. Solo hace falta nombre cuando el número es nuevo en tu cuenta. | objeto `client`                             |
| **Servicio**     | *Para qué* es la cita ("Consulta", "Corte de pelo").                                                                                                     | `service_id` **o** `service_name`           |
| **Profesional**  | *Con quién* es la cita.                                                                                                                                  | `professional_id` **o** `professional_name` |
| **Tipo de cita** | El *formato* (Presencial, Videollamada, Llamada).                                                                                                        | `event_type_id` **o** `event_type_name`     |

Para cada uno de los tres últimos, envía **el ID o el nombre**. Los IDs se comparan de forma
exacta. Los nombres se comparan sin distinguir mayúsculas ni acentos, así que `consulta medica`
encuentra `Consulta Médica`. Si envías ambos, se usa el ID.

Llama a **List bookable services** una vez para ver los IDs y nombres exactos que acepta tu
cuenta:

```json theme={null}
{
  "status": "success",
  "data": [
    {
      "id": 12,
      "name": "Consulta Médica",
      "default_duration_minutes": 30,
      "professionals": [ { "id": 4, "name": "Dra. Ana Gómez" }, { "id": 7, "name": "Dr. Luis Peña" } ],
      "event_types": [ { "id": 1, "name": "In-Person" }, { "id": 2, "name": "Video call" } ]
    }
  ]
}
```

## Horas y el campo `timezone`

Envía la hora local que le diste al cliente, más la zona IANA a la que pertenece:

```json theme={null}
{ "start_at": "2026-09-15T14:00:00", "end_at": "2026-09-15T14:30:00", "timezone": "America/Bogota" }
```

No tienes que calcular el desfase UTC ni preocuparte por el horario de verano: las reglas de
esa zona en esa fecha se aplican por ti. Si lo prefieres, incluye un desfase explícito
(`2026-09-15T09:00:00-05:00`); entonces el desfase prevalece sobre `timezone`, que sigue
siendo obligatorio.

`end_at` es obligatorio y nunca se deriva de la duración por defecto del servicio: cuánto dura
la cita es una afirmación tuya, no algo que la API deduzca.

## Dos cosas que esta API hace distinto

1. **Nunca rechaza por disponibilidad.** Si la hora cae fuera del horario laboral o choca con
   otra cita, se agenda igualmente. Tu sistema es dueño de la agenda; Dialtu la registra. No
   verás un `409` en una reserva normal.
2. **No decide qué mensajes salen.** Que el cliente reciba una solicitud de confirmación o
   recordatorios, y con cuánta antelación, viene de la configuración del propio calendario en
   Dialtu (**Calendario → Configuración → Notificaciones**). Una cita agendada por aquí recibe
   exactamente los mismos mensajes que una agendada en el panel. No hay campos para ello, a
   propósito: esos mensajes se facturan a la cuenta de Dialtu, así que los elige el dueño de la
   cuenta.

## Una reserva de principio a fin

```bash theme={null}
curl -X POST https://api.dialtu.com/api/v2/public/calendar/events \
  -H "Authorization: Bearer pk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "client": { "first_name": "Jane", "last_name": "Roe", "phone": "+573001112233", "email": "jane.roe@example.com" },
    "service_name": "Consulta Médica",
    "professional_name": "Ana Gómez",
    "event_type_name": "In-Person",
    "start_at": "2026-09-15T14:00:00",
    "end_at": "2026-09-15T14:30:00",
    "timezone": "America/Bogota"
  }'
```

```json theme={null}
{
  "status": "success",
  "data": {
    "id": 8811,
    "start_at": "2026-09-15T19:00:00Z",
    "end_at": "2026-09-15T19:30:00Z",
    "status": "booked",
    "source": "api",
    "confirmation_status": "pending",
    "client": { "id": 512, "name": "Jane Roe", "phone": "+573001112233" },
    "calendar_profile": { "calendar_profile_id": 4, "name": "Dra. Ana Gómez" },
    "service": { "id": 12, "name": "Consulta Médica", "color": "#6633ff" },
    "event_type": { "id": 1, "name": "In-Person", "color": "#2b8a3e" },
    "custom_fields": { "booked_by": "api" },
    "created_at": "2026-09-02T18:04:11Z"
  },
  "client_id": 512,
  "client_created": true
}
```

Guarda `data.id`: es el ID de la cita en Dialtu. `client_created` indica si la solicitud creó
el cliente (`true`) o coincidió con uno existente (`false`).

## Comprobar la capacidad antes

**Get bookable capacity per service** responde "¿cuántas citas más caben?" por servicio en un
rango de fechas. `capacity` se suma **por profesional**, no por instante — tres profesionales
libres a las 09:00 son tres clientes a los que puedes llamar, no un hueco — y es una **cota
superior**: reservar un hueco puede eliminar más de un candidato cuando interactúan los
márgenes. Mantén `days` alineado con la ventana de búsqueda del agente que hará las llamadas,
para no encolar clientes a los que el agente luego dirá que no hay disponibilidad.

## Conectarlo con n8n

<Steps>
  <Step title="Nodo HTTP Request">
    Método `POST`, URL `https://api.dialtu.com/api/v2/public/calendar/events`.
  </Step>

  <Step title="Autenticación">
    *Generic Credential Type* → *Header Auth*, nombre `Authorization`, valor `Bearer pk_xxxxxxxx`.
  </Step>

  <Step title="Cuerpo">
    **Body Content Type** `JSON`; pega el cuerpo de arriba y sustituye los valores por
    expresiones de tus nodos anteriores. Consulta una vez los nombres de servicio, profesional
    y tipo de cita con **List bookable services** y deja los IDs fijos: nada es opcional.
  </Step>

  <Step title="Ante un error">
    Lee `error_code` del cuerpo de la respuesta. Ningún `400` merece reintentarse sin cambios;
    un `500` sí. Ver [Errores](/es/api-reference/errores#calendario--reservas).
  </Step>
</Steps>

## Todavía no disponible

Leer, listar, reprogramar y cancelar citas por la API no está implementado. Cancela o mueve una
cita desde el panel de Dialtu. Si eliminas la cita en tu sistema, la de Dialtu se queda:
cancélala a mano.
