Integraciones
Google Calendar
Sincronización bidireccional con Google Calendar en Coordinalo
Google Calendar
Coordinalo sincroniza sesiones con Google Calendar de forma bidireccional, permitiendo que los proveedores vean sus citas en su calendario personal y que eventos externos bloqueen disponibilidad.
Flujo de sincronización
Coordinalo ←→ Google Calendar
→ Sesiones de Coordinalo aparecen en el calendario del proveedor
← Eventos externos en Google bloquean disponibilidad en CoordinaloConectar calendario
Iniciar conexión OAuth
POST /api/v1/providers/:providerId/calendar/connectCuerpo de la solicitud
{
"provider": "google",
"calendarId": "primary"
}Respuesta
{
"authUrl": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...",
"state": "state_abc123",
"expiresAt": "2026-01-20T10:10:00Z"
}Redirige al proveedor a authUrl para que autorice el acceso a su calendario.
Callback de OAuth
GET /api/v1/calendar/callback?code=xxx&state=state_abc123Coordinalo procesa el código de autorización y completa la conexión.
Verificar estado de conexión
GET /api/v1/providers/:providerId/calendar/statusRespuesta
{
"connected": true,
"provider": "google",
"email": "maria@gmail.com",
"calendarId": "primary",
"calendarName": "Calendario principal",
"connectedAt": "2026-01-15T10:00:00Z",
"lastSync": "2026-01-20T08:00:00Z",
"syncStatus": "active",
"settings": {
"syncDirection": "bidirectional",
"blockOnExternalEvents": true,
"syncFrequency": "realtime"
}
}Configuración de sincronización
Actualizar configuración
PUT /api/v1/providers/:providerId/calendar/settingsCuerpo de la solicitud
{
"syncDirection": "bidirectional",
"blockOnExternalEvents": true,
"syncFrequency": "realtime",
"eventDefaults": {
"colorId": "9",
"reminderMinutes": [30, 10],
"visibility": "private"
},
"blockingRules": {
"allDayEvents": true,
"busyEvents": true,
"tentativeEvents": false,
"specificCalendars": ["primary", "work@company.com"]
}
}Opciones de sincronización
| Opción | Valores | Descripción |
|---|---|---|
syncDirection | bidirectional, to_google, from_google | Dirección de sincronización |
blockOnExternalEvents | true, false | Bloquear disponibilidad por eventos externos |
syncFrequency | realtime, hourly, daily | Frecuencia de sincronización |
Reglas de bloqueo
| Regla | Descripción |
|---|---|
allDayEvents | Eventos de día completo bloquean todo el día |
busyEvents | Solo eventos marcados como "ocupado" bloquean |
tentativeEvents | Eventos tentativos también bloquean |
specificCalendars | Lista de calendarios a considerar |
Sincronización manual
Forzar sincronización
POST /api/v1/providers/:providerId/calendar/syncCuerpo de la solicitud (opcional)
{
"direction": "both",
"from": "2026-01-01",
"to": "2026-02-28"
}Respuesta
{
"syncId": "sync_abc123",
"status": "completed",
"results": {
"toGoogle": {
"created": 15,
"updated": 3,
"deleted": 1
},
"fromGoogle": {
"blocksCreated": 5,
"blocksRemoved": 2
}
},
"completedAt": "2026-01-20T10:00:30Z"
}Eventos en Google Calendar
Formato de eventos creados
Cuando Coordinalo crea un evento en Google Calendar:
{
"summary": "Kinesiología - Juan Pérez",
"description": "Sesión de kinesiología\n\nCliente: Juan Pérez\nTeléfono: +56912345678\n\nVer en Coordinalo: https://app.coordinalo.com/sessions/sess_001",
"start": {
"dateTime": "2026-01-21T10:00:00-03:00",
"timeZone": "America/Santiago"
},
"end": {
"dateTime": "2026-01-21T11:00:00-03:00",
"timeZone": "America/Santiago"
},
"location": "Av. Principal 123, Santiago",
"colorId": "9",
"reminders": {
"useDefault": false,
"overrides": [
{ "method": "popup", "minutes": 30 },
{ "method": "popup", "minutes": 10 }
]
},
"extendedProperties": {
"private": {
"coordinalo_session_id": "sess_001",
"coordinalo_org_id": "org_abc123"
}
}
}Personalizar formato de eventos
PUT /api/v1/providers/:providerId/calendar/event-formatCuerpo de la solicitud
{
"summaryTemplate": "{{service}} - {{clientName}}",
"descriptionTemplate": "Cliente: {{clientName}}\nTeléfono: {{clientPhone}}\nNotas: {{notes}}",
"includeLocation": true,
"includeCoordinaloLink": true,
"colorByService": {
"kinesiologia": "9",
"masoterapia": "5",
"default": "1"
}
}Bloqueos de disponibilidad
Ver bloqueos importados
GET /api/v1/providers/:providerId/calendar/blocksRespuesta
{
"data": [
{
"id": "block_001",
"source": "google_calendar",
"googleEventId": "event_xyz789",
"title": "Reunión de trabajo",
"start": "2026-01-21T14:00:00Z",
"end": "2026-01-21T15:00:00Z",
"allDay": false,
"calendarId": "work@company.com",
"syncedAt": "2026-01-20T08:00:00Z"
},
{
"id": "block_002",
"source": "google_calendar",
"googleEventId": "event_abc123",
"title": "Vacaciones",
"start": "2026-02-01",
"end": "2026-02-08",
"allDay": true,
"calendarId": "primary",
"syncedAt": "2026-01-20T08:00:00Z"
}
]
}Excluir evento de bloqueo
POST /api/v1/providers/:providerId/calendar/blocks/:blockId/exclude{
"excluded": true,
"reason": "Este evento no afecta mi disponibilidad"
}Calendarios múltiples
Listar calendarios disponibles
GET /api/v1/providers/:providerId/calendar/available-calendarsRespuesta
{
"calendars": [
{
"id": "primary",
"name": "Calendario principal",
"accessRole": "owner",
"selected": true
},
{
"id": "work@company.com",
"name": "Trabajo",
"accessRole": "writer",
"selected": true
},
{
"id": "family@group.calendar.google.com",
"name": "Familia",
"accessRole": "reader",
"selected": false
}
]
}Seleccionar calendarios a sincronizar
PUT /api/v1/providers/:providerId/calendar/selected-calendarsCuerpo de la solicitud
{
"writeCalendar": "primary",
"readCalendars": ["primary", "work@company.com"]
}Resolución de conflictos
Política de conflictos
PUT /api/v1/providers/:providerId/calendar/conflict-policyCuerpo de la solicitud
{
"onGoogleConflict": "block_coordinalo",
"onCoordinaloConflict": "notify_admin",
"allowDoubleBooking": false,
"bufferMinutes": 15
}| Política | Descripción |
|---|---|
block_coordinalo | Evento de Google bloquea, no se puede agendar en Coordinalo |
notify_admin | Permite agendar pero notifica al admin |
ignore | Ignora conflictos |
Desconectar calendario
POST /api/v1/providers/:providerId/calendar/disconnectCuerpo de la solicitud (opcional)
{
"deleteGoogleEvents": false,
"keepBlocks": false
}Respuesta
{
"disconnected": true,
"disconnectedAt": "2026-01-20T16:00:00Z",
"eventsDeleted": 0,
"blocksRemoved": 5
}Logs de sincronización
GET /api/v1/providers/:providerId/calendar/sync-logsRespuesta
{
"data": [
{
"id": "sync_001",
"type": "automatic",
"direction": "bidirectional",
"status": "completed",
"startedAt": "2026-01-20T08:00:00Z",
"completedAt": "2026-01-20T08:00:05Z",
"results": {
"toGoogle": { "created": 2, "updated": 0, "deleted": 0 },
"fromGoogle": { "blocksCreated": 1, "blocksRemoved": 0 }
}
}
]
}Webhooks
| Evento | Descripción |
|---|---|
calendar.connected | Calendario conectado |
calendar.disconnected | Calendario desconectado |
calendar.sync_completed | Sincronización completada |
calendar.sync_failed | Error en sincronización |
calendar.conflict_detected | Conflicto de horario detectado |
Ejemplo de webhook
{
"event": "calendar.conflict_detected",
"data": {
"providerId": "prov_001",
"providerName": "María González",
"coordinaloSession": {
"id": "sess_001",
"startTime": "2026-01-21T10:00:00Z"
},
"googleEvent": {
"id": "event_xyz789",
"title": "Reunión importante",
"startTime": "2026-01-21T09:30:00Z",
"endTime": "2026-01-21T10:30:00Z"
}
},
"timestamp": "2026-01-20T10:00:01Z"
}