TL;DR
Las APIs de Calendly te permiten automatizar los flujos de trabajo de programación. Te autenticas con OAuth 2.0, accedes a tipos de eventos y reservas a través de api.calendly.com, y recibes actualizaciones en tiempo real a través de webhooks. Para las pruebas, usa Apidog para validar las cargas útiles de los webhooks y probar tu integración sin crear reservas reales.
Introducción
Calendly procesa millones de reuniones mensualmente. La gente lo usa para llamadas de ventas, sesiones de soporte, consultas y entrevistas. La API te permite integrar esa capacidad de programación en tus propias aplicaciones.
El patrón común: quieres que las reservas de Calendly activen acciones en tu sistema. Un usuario reserva una demostración y tu CRM se actualiza. Se programa una consulta y envías un cuestionario. Se cancela una reunión y notificas a tu equipo.
La API de Calendly maneja esto a través de webhooks. Cuando ocurren eventos (reserva creada, cancelada, reprogramada), Calendly envía POST a tus endpoints. Tú procesas la carga útil y tomas acción.
Autenticación con OAuth 2.0
Calendly utiliza OAuth 2.0 para el acceso a la API. No puedes simplemente usar una clave de API.
Crear una aplicación OAuth
- Ve a Calendly → Integraciones → API y Webhooks
- Haz clic en "Crear Nueva Aplicación"
- Establece tu URI de redirección (por ejemplo,
https://tuapp.com/auth/calendly/callback) - Obtén tu ID de cliente y secreto de cliente
El flujo de OAuth
Paso 1: Redirigir al usuario para autorizar
https://auth.calendly.com/oauth/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=https://yourapp.com/auth/calendly/callback
Paso 2: El usuario autoriza y es redirigido de vuelta
https://yourapp.com/auth/calendly/callback?code=AUTHORIZATION_CODE
Paso 3: Intercambiar el código por un token de acceso
const response = await fetch('https://auth.calendly.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64')
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authCode,
redirect_uri: 'https://yourapp.com/auth/calendly/callback'
})
})
const { access_token, refresh_token, expires_in } = await response.json()
Paso 4: Usar el token
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Tokens de actualización
Los tokens de acceso expiran después de 2 horas. Usa tokens de actualización para obtener nuevos:
const response = await fetch('https://auth.calendly.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64')
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: storedRefreshToken
})
})
Obteniendo información del usuario
Obtener usuario actual
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Respuesta:
{
"resource": {
"avatar_url": "https://calendly.com/avatar.jpg",
"created_at": "2024-01-15T10:00:00Z",
"current_organization": "https://api.calendly.com/organizations/ABC123",
"email": "you@example.com",
"name": "John Doe",
"scheduling_url": "https://calendly.com/johndoe",
"slug": "johndoe",
"timezone": "America/New_York",
"uri": "https://api.calendly.com/users/ABC123"
}
}
Obtener membresía de la organización
curl -X GET "https://api.calendly.com/organization_memberships/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Tipos de eventos
Los tipos de eventos son las plantillas de reunión que los usuarios crean (llamada de 30 minutos, consulta de 60 minutos, etc.).
Listar tipos de eventos
curl -X GET "https://api.calendly.com/event_types?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Respuesta:
{
"resource": {
"uri": "https://api.calendly.com/event_types/ETC123",
"active": true,
"booking_method": "instant",
"color": "#0066FF",
"created_at": "2024-01-15T10:00:00Z",
"description_html": "<p>30-minute consultation</p>",
"duration": 30,
"internal_note": "Use Zoom link",
"kind": "solo",
"name": "30 Min Consultation",
"pooling_type": null,
"profile": {
"name": "John Doe",
"type": "User",
"owner": "https://api.calendly.com/users/ABC123"
},
"scheduling_url": "https://calendly.com/johndoe/30min",
"slug": "30min",
"type": "StandardEventType"
},
"pagination": {
"count": 1,
"next_page": null
}
}
Obtener un tipo de evento específico
curl -X GET "https://api.calendly.com/event_types/ETC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Eventos programados (reservas)
Los eventos son las reservas reales realizadas a través de Calendly.
Listar eventos programados
curl -X GET "https://api.calendly.com/scheduled_events?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Filtrar por rango de fechas:
curl -X GET "https://api.calendly.com/scheduled_events?min_start_time=2026-03-01T00:00:00Z&max_start_time=2026-03-31T23:59:59Z" \
-H "Authorization: Bearer ACCESS_TOKEN"
Respuesta:
{
"resource": {
"uri": "https://api.calendly.com/scheduled_events/ABC123",
"status": "active",
"tracking": {
"utm_campaign": "spring_sale",
"utm_source": "email",
"utm_medium": "newsletter"
},
"created_at": "2026-03-24T10:00:00Z",
"end_time": "2026-03-25T11:00:00Z",
"event_type": "https://api.calendly.com/event_types/ETC123",
"invitees_counter": {
"active": 1,
"limit": 1,
"total": 1
},
"location": {
"type": "zoom",
"join_url": "https://zoom.us/j/123456789"
},
"start_time": "2026-03-25T10:30:00Z",
"updated_at": "2026-03-24T10:00:00Z"
}
}
Obtener detalles del evento
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Obtener invitados para un evento
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID/invitees" \
-H "Authorization: Bearer ACCESS_TOKEN"
Respuesta:
{
"resource": [
{
"cancel_url": "https://calendly.com/cancellations/ABC123",
"created_at": "2026-03-24T10:00:00Z",
"email": "jane@example.com",
"event": "https://api.calendly.com/scheduled_events/ABC123",
"name": "Jane Smith",
"new_invitee": null,
"old_invitee": null,
"reschedule_url": "https://calendly.com/reschedulings/ABC123",
"status": "active",
"text_reminder_number": "+15551234567",
"timezone": "America/New_York",
"tracking": {
"utm_campaign": null,
"utm_source": null
},
"updated_at": "2026-03-24T10:00:00Z",
"uri": "https://api.calendly.com/scheduled_event_invitees/INV123",
"canceled": null
}
]
}
Webhooks para actualizaciones en tiempo real
Los webhooks notifican a tu aplicación sobre eventos de reserva en tiempo real.
Crear una suscripción de webhook
curl -X POST "https://api.calendly.com/webhook_subscriptions" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tuapp.com/webhooks/calendly",
"events": [
"invitee.created",
"invitee.canceled",
"invitee.rescheduled"
],
"organization": "https://api.calendly.com/organizations/ORG123",
"scope": "organization"
}'
Eventos disponibles:
invitee.created- Nueva reserva realizadainvitee.canceled- Reserva canceladainvitee.rescheduled- Reserva reprogramada
Listar suscripciones de webhook
curl -X GET "https://api.calendly.com/webhook_subscriptions?organization=https://api.calendly.com/organizations/ORG123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Eliminar un webhook
curl -X DELETE "https://api.calendly.com/webhook_subscriptions/WEBHOOK_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Manejo de cargas útiles de webhook
Verificar firmas de webhook
Calendly firma los webhooks con una firma en el encabezado Calendly-Webhook-Signature:
import crypto from 'crypto'
function verifySignature(payload, signature, secret) {
const [t, v1] = signature.split(',')
const timestamp = t.split('=')[1]
const hash = v1.split('=')[1]
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(expectedSignature)
)
}
app.post('/webhooks/calendly', (req, res) => {
const signature = req.headers['calendly-webhook-signature']
const payload = JSON.stringify(req.body)
if (!verifySignature(payload, signature, process.env.CALENDLY_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
// Procesar webhook
handleWebhook(req.body)
res.status(200).send('OK')
})
Procesar eventos de reserva
function handleWebhook(payload) {
const { event, payload: data } = payload
switch (event) {
case 'invitee.created':
console.log(`Nueva reserva: ${data.event.start_time}`)
console.log(`Invitado: ${data.email}`)
// Añadir a CRM, enviar correo de confirmación, etc.
syncToCRM(data)
break
case 'invitee.canceled':
console.log(`Reserva cancelada: ${data.event.uri}`)
// Actualizar CRM, notificar al equipo, etc.
removeFromCRM(data)
break
case 'invitee.rescheduled':
console.log(`Reserva reprogramada: ${data.event.start_time}`)
// Actualizar calendario, notificar al equipo, etc.
updateCRM(data)
break
}
}
Pruebas con Apidog
La API de Calendly requiere OAuth, lo que complica las pruebas. Apidog simplifica esto.

1. Simular respuestas de OAuth
Durante el desarrollo, no realices el flujo completo de OAuth cada vez. Simula la respuesta del token:
{
"access_token": "mock_access_token",
"refresh_token": "mock_refresh_token",
"expires_in": 7200,
"created_at": 1700000000
}
2. Probar manejadores de webhooks
Crea cargas útiles de webhook simuladas:
{
"created_at": "2026-03-24T10:00:00Z",
"event": "invitee.created",
"payload": {
"email": "test@example.com",
"name": "Test User",
"event": {
"start_time": "2026-03-25T10:30:00Z",
"end_time": "2026-03-25T11:00:00Z",
"event_type": {
"name": "30 Min Consultation"
}
}
}
}
Envía a tu endpoint de webhook y verifica el manejo.
3. Variables de entorno
CALENDLY_CLIENT_ID: abc123
CALENDLY_CLIENT_SECRET: xyz789
CALENDLY_ACCESS_TOKEN: stored_token
CALENDLY_REFRESH_TOKEN: stored_refresh
CALENDLY_WEBHOOK_SECRET: webhook_signing_secret
4. Validar firmas de webhook
pm.test('Webhook signature is valid', () => {
const signature = pm.request.headers.get('Calendly-Webhook-Signature')
pm.expect(signature).to.exist
const payload = pm.request.body.raw
const secret = pm.environment.get('CALENDLY_WEBHOOK_SECRET')
// Verify signature
const valid = verifySignature(payload, signature, secret)
pm.expect(valid).to.be.true
})
Prueba webhooks de Calendly con Apidog - gratis
Errores comunes y soluciones
401 No autorizado
Causa: Token inválido o expirado.
Solución:
- Verifica que el token no haya expirado (expira en 2 horas)
- Usa el token de actualización para obtener un nuevo token de acceso
- Asegúrate de que el encabezado de Autorización sea
Bearer {token}
403 Prohibido
Causa: Alcance de OAuth insuficiente.
Solución: El token de OAuth necesita los alcances apropiados. Al solicitar autorización, incluye los alcances necesarios. Los alcances de Calendly son implícitos según lo que el usuario autorice.
404 No encontrado
Causa: El recurso no existe o el usuario carece de acceso.
Solución:
- Verifica que el URI del recurso sea correcto
- Asegúrate de que el usuario autenticado tenga acceso al recurso
- Verifica que el tipo de evento o ID de evento sea válido
422 Entidad no procesable
Causa: Error de validación en la solicitud.
Solución: Revisa la respuesta para obtener detalles:
{
"title": "Error de validación",
"message": "Parámetro inválido: la URL debe ser una URL HTTPS válida"
}
Alternativas y comparaciones
| Característica | Calendly | Acuity | Cal.com | Calendly |
|---|---|---|---|---|
| Nivel gratuito | Limitado | Limitado | Auto-alojado gratis | ✓ |
| Acceso API | ✓ | ✓ | ✓ | ✓ |
| Webhooks | ✓ | ✓ | ✓ | ✓ |
| OAuth | ✓ | Clave API | Clave API | OAuth |
| Programación en equipo | ✓ | ✓ | ✓ | ✓ |
| Código abierto | No | No | Sí | No |
Calendly tiene la documentación de API y el flujo de OAuth más pulidos. Cal.com es la alternativa de código abierto con una autenticación de clave de API más simple.
Casos de uso en el mundo real
Integración con CRM de ventas. Una empresa SaaS B2B integra Calendly en su página de precios. Cuando alguien reserva una demostración, el webhook activa:
- Crear un lead en Salesforce
- Enviar notificación de Slack al equipo de ventas
- Añadir a la secuencia de automatización de marketing
- Registrar actividad en la plataforma de éxito del cliente
Plataforma de consulta. Una plataforma de servicios legales permite a los clientes reservar consultas con abogados. La integración de la API:
- Sincroniza las reservas con el sistema de programación interno
- Genera enlaces de reunión de Zoom
- Envía un cuestionario de admisión 24 horas antes
- Crea un expediente cuando la reunión finaliza
Programación de entrevistas. Una plataforma de reclutamiento utiliza Calendly para entrevistas con candidatos. Los webhooks:
- Actualizan el ATS con los detalles de la entrevista
- Notifican al gerente de contratación por correo electrónico
- Envían invitaciones de calendario a todos los participantes
- Realizan un seguimiento de los ausentes para un seguimiento
Conclusión
Esto es lo que has aprendido:
- Calendly utiliza OAuth 2.0 para la autenticación de la API
- Accede a tipos de eventos y eventos programados a través de la API
- Los webhooks proporcionan notificaciones de reserva en tiempo real
- Siempre verifica las firmas de los webhooks por seguridad
- Prueba con Apidog antes de conectarte a calendarios reales
Tus próximos pasos:
- Crea una aplicación OAuth en Calendly
- Implementa el flujo de OAuth
- Configura una suscripción de webhook
- Prueba con cargas útiles simuladas en Apidog
- Despliega en producción
Prueba webhooks de Calendly con Apidog - gratis
Preguntas frecuentes
¿Necesito un plan de pago de Calendly para usar la API?No. La API está disponible en todos los planes, incluyendo el gratuito. Sin embargo, los planes gratuitos tienen características limitadas. Los webhooks están disponibles en todos los planes.
¿Cuál es la diferencia entre los webhooks a nivel de usuario y a nivel de organización?Los webhooks a nivel de usuario solo capturan eventos para un usuario. Los webhooks a nivel de organización capturan eventos para todos los miembros del equipo. La mayoría de las integraciones usan el alcance de la organización.
¿Cómo obtengo el secreto de firma del webhook?Cuando creas un webhook a través de la API, la respuesta incluye una signing_key. Almacena esto de forma segura. Se utiliza para verificar las firmas de los webhooks.
¿Puedo crear reservas a través de la API?No. Calendly no tiene un endpoint de API para crear reservas. Las reservas deben realizarse a través de la interfaz de usuario de Calendly o widgets incrustados. La API es de solo lectura para las reservas.
¿Cómo manejo las conversiones de zona horaria?Todas las marcas de tiempo en la API están en UTC (ISO 8601). Convierte a la hora local en tu aplicación. La zona horaria del usuario está disponible en el recurso del usuario.
¿Cuál es el límite de velocidad?Calendly no documenta públicamente los límites de velocidad. Utiliza patrones de solicitud razonables. Si alcanzas los límites, implementa una retirada exponencial.
¿Puedo obtener reservas históricas?Sí. Usa min_start_time y max_start_time para consultar eventos históricos. No hay límite en cuanto a qué tan atrás puedes consultar.
¿Cómo pruebo el flujo de OAuth localmente?Usa un servicio de túnel como ngrok para exponer tu servidor local. Configura la URI de redirección a tu URL de ngrok. Completa el flujo de OAuth en un navegador y luego inspecciona la devolución de llamada.
