Resumo
As APIs do Calendly permitem automatizar fluxos de trabalho de agendamento. Você se autentica com OAuth 2.0, acessa tipos de eventos e agendamentos via api.calendly.com, e recebe atualizações em tempo real via webhooks. Para testar integrações, utilize o Apidog para validar payloads de webhook sem precisar criar agendamentos reais.
Introdução
O Calendly processa milhões de reuniões por mês e é amplamente usado para chamadas de vendas, sessões de suporte, consultorias e entrevistas. A API permite incorporar funcionalidades de agendamento diretamente em seus aplicativos.
O fluxo mais comum: agendamentos do Calendly disparam ações no seu sistema — como atualizar um CRM após uma demonstração agendada, enviar questionários antes de consultorias, ou notificar equipes sobre cancelamentos.
A API do Calendly gerencia isso via webhooks: sempre que eventos ocorrem (criação, cancelamento, reagendamento), o Calendly envia POSTs para seus endpoints. Seu sistema processa o payload e executa as ações necessárias.
💡 Dica: Se está integrando agendamento, o Apidog facilita testar manipuladores de webhook e validar payloads. Simule respostas do Calendly e garanta que sua integração cubra todos os eventos antes de conectar a calendários reais.
Autenticação com OAuth 2.0
O Calendly utiliza OAuth 2.0 para acesso à API. Não é possível autenticar apenas com chave de API.
Criar um aplicativo OAuth
- Acesse Calendly → Integrações → API & Webhooks
- Clique em “Criar Novo Aplicativo”
- Configure sua URI de redirecionamento (ex.:
https://yourapp.com/auth/calendly/callback) - Salve o client ID e client secret
O fluxo OAuth
Passo 1: Redirecione o usuário para autorização
https://auth.calendly.com/oauth/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=https://yourapp.com/auth/calendly/callback
Passo 2: Usuário autoriza e retorna para seu callback
https://yourapp.com/auth/calendly/callback?code=AUTHORIZATION_CODE
Passo 3: Troque o código por um token de acesso
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()
Passo 4: Use o token para acessar a API
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Tokens de atualização
Tokens de acesso expiram em 2 horas. Use o refresh token para obter um novo:
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
})
})
Obtendo informações do usuário
Obter usuário atual
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Resposta:
{
"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"
}
}
Obter associação à organização
curl -X GET "https://api.calendly.com/organization_memberships/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Tipos de evento
Tipos de evento são modelos de reunião criados (ex: chamada 30 min, consultoria 60 min, etc).
Listar tipos de evento
curl -X GET "https://api.calendly.com/event_types?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Resposta:
{
"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
}
}
Obter um tipo de evento específico
curl -X GET "https://api.calendly.com/event_types/ETC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Eventos agendados (agendamentos)
Eventos são os agendamentos reais feitos via Calendly.
Listar eventos agendados
curl -X GET "https://api.calendly.com/scheduled_events?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Filtrar por datas:
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"
Resposta:
{
"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"
}
}
Obter detalhes do evento
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Obter convidados para um evento
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID/invitees" \
-H "Authorization: Bearer ACCESS_TOKEN"
Resposta:
{
"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 atualizações em tempo real
Webhooks notificam seu app sobre eventos de agendamento em tempo real.
Criar uma assinatura de webhook
curl -X POST "https://api.calendly.com/webhook_subscriptions" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/calendly",
"events": [
"invitee.created",
"invitee.canceled",
"invitee.rescheduled"
],
"organization": "https://api.calendly.com/organizations/ORG123",
"scope": "organization"
}'
Eventos disponíveis:
-
invitee.created— agendamento criado -
invitee.canceled— agendamento cancelado -
invitee.rescheduled— agendamento reagendado
Listar assinaturas de webhook
curl -X GET "https://api.calendly.com/webhook_subscriptions?organization=https://api.calendly.com/organizations/ORG123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Excluir um webhook
curl -X DELETE "https://api.calendly.com/webhook_subscriptions/WEBHOOK_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Manipulando payloads de webhook
Verificar assinaturas de webhook
O Calendly assina webhooks no cabeçalho Calendly-Webhook-Signature. Exemplo de validação em Node.js:
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')
}
// Processar webhook
handleWebhook(req.body)
res.status(200).send('OK')
})
Processar eventos de agendamento
function handleWebhook(payload) {
const { event, payload: data } = payload
switch (event) {
case 'invitee.created':
console.log(`Novo agendamento: ${data.event.start_time}`)
console.log(`Convidado: ${data.email}`)
// Adicione ao CRM, envie e-mail de confirmação, etc.
syncToCRM(data)
break
case 'invitee.canceled':
console.log(`Agendamento cancelado: ${data.event.uri}`)
// Atualize CRM, notifique equipe, etc.
removeFromCRM(data)
break
case 'invitee.rescheduled':
console.log(`Agendamento reagendado: ${data.event.start_time}`)
// Atualize calendário, notifique equipe, etc.
updateCRM(data)
break
}
}
Testando com Apidog
A API do Calendly exige OAuth, dificultando testes rápidos. O Apidog simplifica esse processo.
1. Simular respostas OAuth
Durante o desenvolvimento, simule a resposta do token para não executar o fluxo OAuth sempre:
{
"access_token": "mock_access_token",
"refresh_token": "mock_refresh_token",
"expires_in": 7200,
"created_at": 1700000000
}
2. Testar manipuladores de webhook
Monte payloads simulados de webhook:
{
"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"
}
}
}
}
Envie para seu endpoint e verifique o processamento.
3. Variáveis de ambiente
Utilize variáveis de ambiente para facilitar os testes:
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 assinaturas de webhook
Teste a validação da assinatura no Apidog:
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')
// Verifique assinatura
const valid = verifySignature(payload, signature, secret)
pm.expect(valid).to.be.true
})
Teste webhooks do Calendly com o Apidog — grátis.
Erros comuns e soluções
401 Não Autorizado
Causa: Token inválido ou expirado.
Solução:
- Confira se o token não expirou (expira em 2h)
- Use o refresh token para renovar o access token
- Certifique-se de enviar o header
Authorization: Bearer {token}
403 Proibido
Causa: Escopo OAuth insuficiente.
Solução: Solicite a autorização com escopos corretos; o Calendly define escopos conforme aceito pelo usuário.
404 Não Encontrado
Causa: Recurso inexistente ou sem acesso.
Solução:
- Verifique a URI
- Confirme o acesso do usuário autenticado
- Garanta que os IDs sejam válidos
422 Entidade Não Processável
Causa: Erro de validação na requisição.
Solução: Veja a resposta detalhada:
{
"title": "Validation Error",
"message": "Invalid parameter: url must be a valid HTTPS URL"
}
Alternativas e comparações
| Recurso | Calendly | Acuity | Cal.com | Calendly |
|---|---|---|---|---|
| Camada gratuita | Limitada | Limitada | Auto-hospedado grátis | ✓ |
| Acesso à API | ✓ | ✓ | ✓ | ✓ |
| Webhooks | ✓ | ✓ | ✓ | ✓ |
| OAuth | ✓ | Chave de API | Chave de API | OAuth |
| Agendamento em equipe | ✓ | ✓ | ✓ | ✓ |
| Código aberto | Não | Não | Sim | Não |
O Calendly oferece documentação de API e fluxo OAuth bem polidos. O Cal.com é uma alternativa open source com autenticação baseada em chave de API.
Casos de uso do mundo real
Integração com CRM de vendas:
- Criação de lead no Salesforce
- Notificação via Slack para vendas
- Adição à automação de marketing
- Registro de atividade em plataforma de sucesso do cliente
Plataforma de consultoria:
- Sincronização com sistema interno
- Geração de links Zoom
- Envio de questionário antes da reunião
- Criação de arquivo de caso ao finalizar
Agendamento de entrevistas:
- Atualização de ATS
- Notificação ao gerente de contratação
- Envio de convites de calendário
- Rastreamento de ausências
Conclusão
Resumo das ações práticas:
- O Calendly usa OAuth 2.0 para autenticação de API
- Acesse tipos de eventos e agendamentos via API
- Webhooks notificam sobre eventos em tempo real
- Sempre valide assinaturas de webhooks
- Teste toda a integração com o Apidog antes de conectar a dados reais
Próximos passos:
- Crie um app OAuth no Calendly
- Implemente o fluxo OAuth
- Configure webhooks
- Teste com payloads simulados no Apidog
- Faça o deploy em produção
Teste os webhooks do Calendly com o Apidog — grátis.
Perguntas Frequentes
Preciso de um plano pago do Calendly para usar a API?
Não. A API está disponível em todos os planos, inclusive o gratuito (com limitações). Webhooks também estão disponíveis em todos os planos.
Qual a diferença entre webhooks de usuário e de organização?
Webhooks de usuário capturam eventos de um usuário. Webhooks de organização capturam eventos de toda a equipe. Integrações geralmente usam escopo de organização.
Como obtenho o segredo de assinatura do webhook?
Ao criar um webhook via API, a resposta inclui o campo signing_key. Armazene-o com segurança — ele serve para validar assinaturas dos webhooks.
Posso criar agendamentos via API?
Não. O Calendly não permite criar agendamentos via API; utilize a UI ou widgets. A API é somente leitura para agendamentos.
Como lido com conversão de fuso horário?
Todos os timestamps da API estão em UTC (ISO 8601). Converta para a hora local no seu app. O fuso horário do usuário está no recurso de usuário.
Qual o limite de requisições?
Limites de taxa não são publicados. Use padrões razoáveis e implemente backoff exponencial se necessário.
Consigo obter agendamentos históricos?
Sim. Utilize min_start_time e max_start_time para consultar eventos passados — não há limite de retroatividade.
Como testar o OAuth localmente?
Use um túnel como o ngrok para expor seu servidor local. Aponte a URI de redirecionamento para a URL do ngrok e complete o fluxo OAuth no navegador.

Top comments (0)