Documéntalo
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 Coordinalo

Conectar calendario

Iniciar conexión OAuth

POST /api/v1/providers/:providerId/calendar/connect

Body

{
  "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_abc123

Coordinalo procesa el código de autorización y completa la conexión.

Verificar estado de conexión

GET /api/v1/providers/:providerId/calendar/status

Respuesta

{
  "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/settings

Body

{
  "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ónValoresDescripción
syncDirectionbidirectional, to_google, from_googleDirección de sincronización
blockOnExternalEventstrue, falseBloquear disponibilidad por eventos externos
syncFrequencyrealtime, hourly, dailyFrecuencia de sincronización

Reglas de bloqueo

ReglaDescripción
allDayEventsEventos de día completo bloquean todo el día
busyEventsSolo eventos marcados como "ocupado" bloquean
tentativeEventsEventos tentativos también bloquean
specificCalendarsLista de calendarios a considerar

Sincronización manual

Forzar sincronización

POST /api/v1/providers/:providerId/calendar/sync

Body (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-format

Body

{
  "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/blocks

Respuesta

{
  "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-calendars

Respuesta

{
  "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-calendars

Body

{
  "writeCalendar": "primary",
  "readCalendars": ["primary", "[email protected]"]
}

Resolución de conflictos

Política de conflictos

PUT /api/v1/providers/:providerId/calendar/conflict-policy

Body

{
  "onGoogleConflict": "block_coordinalo",
  "onCoordinaloConflict": "notify_admin",
  "allowDoubleBooking": false,
  "bufferMinutes": 15
}
PolíticaDescripción
block_coordinaloEvento de Google bloquea, no se puede agendar en Coordinalo
notify_adminPermite agendar pero notifica al admin
ignoreIgnora conflictos

Desconectar calendario

POST /api/v1/providers/:providerId/calendar/disconnect

Body (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-logs

Respuesta

{
  "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

EventoDescripción
calendar.connectedCalendario conectado
calendar.disconnectedCalendario desconectado
calendar.sync_completedSincronización completada
calendar.sync_failedError en sincronización
calendar.conflict_detectedConflicto 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"
}

On this page