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/connectBody
{
"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": "[email protected]",
"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/settingsBody
{
"syncDirection": "bidirectional",
"blockOnExternalEvents": true,
"syncFrequency": "realtime",
"eventDefaults": {
"colorId": "9",
"reminderMinutes": [30, 10],
"visibility": "private"
},
"blockingRules": {
"allDayEvents": true,
"busyEvents": true,
"tentativeEvents": false,
"specificCalendars": ["primary", "[email protected]"]
}
}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/syncBody (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-formatBody
{
"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": "[email protected]",
"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": "[email protected]",
"name": "Trabajo",
"accessRole": "writer",
"selected": true
},
{
"id": "[email protected]",
"name": "Familia",
"accessRole": "reader",
"selected": false
}
]
}Seleccionar calendarios a sincronizar
PUT /api/v1/providers/:providerId/calendar/selected-calendarsBody
{
"writeCalendar": "primary",
"readCalendars": ["primary", "[email protected]"]
}Resolución de conflictos
Política de conflictos
PUT /api/v1/providers/:providerId/calendar/conflict-policyBody
{
"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/disconnectBody (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"
}