Conector de Calendly

Conecta Calendly con Brevo a través de Tajo para sincronizar automáticamente los invitados de las reuniones como contactos, activar secuencias de email según los eventos de reserva y optimizar tus flujos de ventas y onboarding.

Resumen

PropiedadValor
PlataformaCalendly
CategoríaAgenda (Personalizada)
Complejidad de configuraciónFácil
Integración oficialNo
Datos sincronizadosEventos, Contactos, Reservas, Cancelaciones
Método de autenticaciónOAuth 2.0 / Personal Access Token

Funcionalidades

  • Sincronización de invitados - Crea contactos de Brevo automáticamente a partir de los invitados a reuniones
  • Disparadores de reservas - Dispara automatizaciones de Brevo cuando se reserven reuniones
  • Gestión de cancelaciones - Activa flujos de reengagement en las cancelaciones
  • Detección de no-shows - Actualiza el estado del contacto cuando un invitado no asista
  • Asignación de tipos de evento - Asocia distintos tipos de evento de Calendly con listas de Brevo
  • Scheduling API - Integra la reserva directamente en tu app sin redirecciones

Requisitos previos

Antes de empezar, asegúrate de tener:

  1. Una cuenta de Calendly (plan Professional o superior para acceso a la API)
  2. Un Personal Access Token desde Calendly Integrations
  3. Una cuenta de Brevo con acceso a la API
  4. Una cuenta de Tajo con permisos de conector

Autenticación

Personal Access Token

Terminal window
# Generate at https://calendly.com/integrations/api_webhooks
export CALENDLY_ACCESS_TOKEN=your_personal_access_token
export TAJO_API_KEY=your_tajo_api_key
export BREVO_API_KEY=your_brevo_api_key

OAuth 2.0

// OAuth 2.0 Authorization Code Flow
const authUrl = 'https://auth.calendly.com/oauth/authorize?' +
new URLSearchParams({
client_id: process.env.CALENDLY_CLIENT_ID,
redirect_uri: 'https://your-app.com/callback',
response_type: 'code'
});
// Exchange code for token
const tokenResponse = await fetch('https://auth.calendly.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
client_id: process.env.CALENDLY_CLIENT_ID,
client_secret: process.env.CALENDLY_CLIENT_SECRET,
redirect_uri: 'https://your-app.com/callback'
})
});

Configuración

Configuración básica

connectors:
calendly:
enabled: true
access_token: "${CALENDLY_ACCESS_TOKEN}"
sync:
contacts: true
events: true
cancellations: true
event_mapping:
discovery_call:
list_id: 10
event_type_uri: "https://api.calendly.com/event_types/abc123"
demo:
list_id: 11
event_type_uri: "https://api.calendly.com/event_types/xyz789"
webhook:
signing_key: "${CALENDLY_WEBHOOK_SIGNING_KEY}"

Asignación de campos

field_mapping:
email: email
name: FIRSTNAME
questions_and_answers:
company: COMPANY
role: JOB_TITLE
phone: SMS
event_type_name: CALENDLY_EVENT_TYPE
scheduled_at: MEETING_DATE
status: BOOKING_STATUS

Endpoints de la API

EndpointMétodoDescripción
https://api.calendly.com/users/meGETObtener el usuario actual
https://api.calendly.com/event_typesGETListar tipos de evento
https://api.calendly.com/scheduled_eventsGETListar eventos programados
https://api.calendly.com/scheduled_events/{uuid}GETObtener un evento programado
https://api.calendly.com/scheduled_events/{uuid}/inviteesGETListar invitados
https://api.calendly.com/scheduling_linksPOSTCrear un enlace de agenda
https://api.calendly.com/webhook_subscriptionsPOSTCrear un webhook
https://api.calendly.com/webhook_subscriptionsGETListar webhooks
https://api.calendly.com/invitee_no_shows/{uuid}GETObtener el estado de no-show

Ejemplos de código

Inicializar el conector

import { TajoClient } from '@tajo/sdk';
const tajo = new TajoClient({
apiKey: process.env.TAJO_API_KEY,
brevoApiKey: process.env.BREVO_API_KEY
});
await tajo.connectors.connect('calendly', {
accessToken: process.env.CALENDLY_ACCESS_TOKEN
});

Listar eventos programados

// Retrieve scheduled events
const response = await fetch(
'https://api.calendly.com/scheduled_events?' +
new URLSearchParams({
user: 'https://api.calendly.com/users/YOUR_USER_ID',
min_start_time: '2024-01-01T00:00:00Z',
max_start_time: '2024-12-31T23:59:59Z',
status: 'active',
count: 100
}),
{
headers: {
'Authorization': `Bearer ${process.env.CALENDLY_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
}
);
const events = await response.json();

Sincronizar invitados con Brevo

// Get invitees for a scheduled event and sync to Brevo
const inviteesResponse = await fetch(
`https://api.calendly.com/scheduled_events/${eventUuid}/invitees`,
{
headers: {
'Authorization': `Bearer ${process.env.CALENDLY_ACCESS_TOKEN}`
}
}
);
const { collection } = await inviteesResponse.json();
for (const invitee of collection) {
await tajo.contacts.sync({
email: invitee.email,
attributes: {
FIRSTNAME: invitee.name,
CALENDLY_EVENT_TYPE: invitee.event,
MEETING_DATE: invitee.created_at,
BOOKING_STATUS: invitee.status
},
listIds: [10]
});
}

Configurar suscripciones de webhook

// Subscribe to Calendly events
const webhook = await fetch(
'https://api.calendly.com/webhook_subscriptions',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.CALENDLY_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://api.tajo.io/webhooks/calendly',
events: [
'invitee.created',
'invitee.canceled',
'invitee_no_show.created'
],
organization: 'https://api.calendly.com/organizations/YOUR_ORG_ID',
scope: 'organization',
signing_key: process.env.CALENDLY_WEBHOOK_SIGNING_KEY
})
}
);

Gestionar eventos de webhook

app.post('/webhooks/calendly', async (req, res) => {
// Verify webhook signature
const signature = req.headers['calendly-webhook-signature'];
const isValid = verifyCalendlySignature(
req.rawBody, signature, process.env.CALENDLY_WEBHOOK_SIGNING_KEY
);
if (!isValid) return res.status(401).send('Unauthorized');
const { event, payload } = req.body;
switch (event) {
case 'invitee.created':
await tajo.contacts.sync({
email: payload.email,
attributes: { BOOKING_STATUS: 'booked' },
listIds: [10]
});
break;
case 'invitee.canceled':
await tajo.contacts.update(payload.email, {
attributes: { BOOKING_STATUS: 'cancelled' }
});
break;
case 'invitee_no_show.created':
await tajo.contacts.update(payload.email, {
attributes: { BOOKING_STATUS: 'no_show' }
});
break;
}
res.status(200).send('OK');
});

Límites de velocidad

RecursoLímiteNotas
Peticiones a la API6.000/minLímite a nivel de organización
Suscripciones de webhook30 por organizaciónEn todos los tipos de evento
Enlaces de agendaIlimitadosSin límite por minuto

Paginación

Las respuestas de la API de Calendly usan paginación basada en cursor. Usa el next_page_token del objeto pagination para obtener más resultados. El tamaño de página por defecto es 20, con un máximo de 100.

Resolución de problemas

ProblemaCausaSolución
No se recibe el webhookScope incorrectoUsa el scope organization para webhooks
401 UnauthorizedToken expiradoGenera un token nuevo o refresca el token OAuth
Faltan datos del invitadoPreguntas sin configurarAñade preguntas personalizadas al tipo de evento
Contactos duplicadosSin lógica de deduplicaciónUsa el email como identificador único para upserts
429 por límite de velocidadDemasiadas peticionesAplica backoff y agrupa peticiones

Modo depuración

connectors:
calendly:
debug: true
log_level: verbose
log_webhooks: true

Buenas prácticas

  1. Usa webhooks - Suscríbete a invitee.created e invitee.canceled para sincronización en tiempo real
  2. Añade preguntas personalizadas - Recoge empresa, puesto y teléfono para perfiles de contacto más completos
  3. Asocia tipos de evento - Asigna distintas listas de Brevo a cada tipo de evento de Calendly
  4. Gestiona los no-shows - Registra los no-shows para ajustar el lead scoring y las secuencias de seguimiento
  5. Usa enlaces de agenda - Genera enlaces únicos para experiencias de reserva personalizadas
  6. Define scope de organización - Usa webhooks a nivel de organización para capturar eventos de todo el equipo

Seguridad

  • OAuth 2.0 - Autenticación basada en tokens con scopes
  • Firmas de webhook - Validación HMAC de firma para webhooks entrantes
  • Solo HTTPS - Todos los endpoints de la API requieren cifrado TLS
  • Expiración de tokens - Los tokens OAuth expiran y requieren flujos de refresh
  • Scopes mínimos - Solicita solo los scopes OAuth necesarios
  • Almacenamiento seguro - Guarda los tokens en variables de entorno o gestores de secretos

Recursos relacionados

Subscribe to updates

developer-docs

Drop your email or phone number — we'll send you what matters next.

auto-detect
Asistente AI

¡Hola! Pregúntame lo que quieras sobre la documentación.