En bref
Les API Calendly permettent d'automatiser vos flux de planification : authentification par OAuth 2.0, accès aux types d'événements et réservations via api.calendly.com, notifications temps réel avec les webhooks. Pour tester vos intégrations, utilisez Apidog afin de valider les charges utiles de webhooks et simuler des réservations sans toucher à la production.
Essayez Apidog dès aujourd'hui
Introduction
Calendly gère des millions de réunions chaque mois pour des appels de vente, du support, des consultations ou entretiens. L'API vous permet d'intégrer la planification directement dans vos applications.
Cas pratique : déclencher des actions automatiques lors d'une réservation Calendly. Par exemple, créer un lead dans votre CRM lors d'une démo réservée, envoyer un questionnaire lors d’une consultation planifiée, ou notifier l’équipe si la réunion est annulée.
L’API Calendly s’appuie sur les webhooks : à chaque événement (création, annulation, replanification), Calendly effectue une requête POST vers votre endpoint. À vous de traiter cette charge utile et d’automatiser vos processus.
💡 Si vous développez des intégrations de planification, Apidog facilite le test de vos gestionnaires de webhooks : simulez les réponses de Calendly, validez toutes les charges utiles, et assurez la robustesse avant la connexion à des calendriers réels.
Authentification avec OAuth 2.0
Calendly n’accepte pas de clé API : l’accès passe obligatoirement par OAuth 2.0.
Créer une application OAuth
- Rendez-vous sur Calendly → Intégrations → API & Webhooks
- Cliquez sur «Créer une nouvelle application»
- Définissez votre URI de redirection (ex :
https://yourapp.com/auth/calendly/callback) - Récupérez votre client ID et secret client
Le flux OAuth
Étape 1 : Rediriger l'utilisateur pour l'autorisation
https://auth.calendly.com/oauth/authorize?
client_id=VOTRE_ID_CLIENT&
response_type=code&
redirect_uri=https://yourapp.com/auth/calendly/callback
Étape 2 : L'utilisateur autorise et est redirigé
https://yourapp.com/auth/calendly/callback?code=CODE_D_AUTORISATION
Étape 3 : Échanger le code contre un jeton d'accès
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()
Étape 4 : Utiliser le jeton
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer JETON_D_ACCES"
Jetons d'actualisation
Les jetons d'accès expirent après 2 heures. Rafraîchissez avec le refresh token :
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
})
})
Obtention des informations utilisateur
Obtenir l'utilisateur actuel
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer JETON_D_ACCES"
Réponse :
{
"resource": {
"avatar_url": "https://calendly.com/avatar.jpg",
"created_at": "2024-01-15T10:00:00Z",
"current_organization": "https://api.calendly.com/organizations/ABC123",
"email": "vous@exemple.com",
"name": "Jean Dupont",
"scheduling_url": "https://calendly.com/jeandupont",
"slug": "jeandupont",
"timezone": "America/New_York",
"uri": "https://api.calendly.com/users/ABC123"
}
}
Obtenir l'adhésion à l'organisation
curl -X GET "https://api.calendly.com/organization_memberships/me" \
-H "Authorization: Bearer JETON_D_ACCES"
Types d'événements
Les types d'événements sont les modèles de réunion (ex : appel 30 min, consultation 60 min).
Lister les types d'événements
curl -X GET "https://api.calendly.com/event_types?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer JETON_D_ACCES"
Réponse :
{
"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>Consultation de 30 minutes</p>",
"duration": 30,
"internal_note": "Utiliser le lien Zoom",
"kind": "solo",
"name": "Consultation de 30 min",
"pooling_type": null,
"profile": {
"name": "Jean Dupont",
"type": "User",
"owner": "https://api.calendly.com/users/ABC123"
},
"scheduling_url": "https://calendly.com/jeandupont/30min",
"slug": "30min",
"type": "StandardEventType"
},
"pagination": {
"count": 1,
"next_page": null
}
}
Obtenir un type d’événement spécifique
curl -X GET "https://api.calendly.com/event_types/ETC123" \
-H "Authorization: Bearer JETON_D_ACCES"
Événements planifiés (réservations)
Les événements correspondent aux réservations concrètes créées via Calendly.
Lister les événements planifiés
curl -X GET "https://api.calendly.com/scheduled_events?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer JETON_D_ACCES"
Pour filtrer par date :
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 JETON_D_ACCES"
Réponse :
{
"resource": {
"uri": "https://api.calendly.com/scheduled_events/ABC123",
"status": "active",
"tracking": {
"utm_campaign": "vente_printemps",
"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"
}
}
Obtenir les détails d’un événement
curl -X GET "https://api.calendly.com/scheduled_events/ID_EVENEMENT" \
-H "Authorization: Bearer JETON_D_ACCES"
Obtenir les invités pour un événement
curl -X GET "https://api.calendly.com/scheduled_events/ID_EVENEMENT/invitees" \
-H "Authorization: Bearer JETON_D_ACCES"
Réponse :
{
"resource": [
{
"cancel_url": "https://calendly.com/cancellations/ABC123",
"created_at": "2026-03-24T10:00:00Z",
"email": "jane@exemple.com",
"event": "https://api.calendly.com/scheduled_events/ABC123",
"name": "Jeanne 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 pour les mises à jour en temps réel
Les webhooks notifient automatiquement votre application en cas de création, annulation ou replanification de réservation.
Créer un abonnement webhook
curl -X POST "https://api.calendly.com/webhook_subscriptions" \
-H "Authorization: Bearer JETON_D_ACCES" \
-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"
}'
Événements disponibles :
-
invitee.created: Nouvelle réservation -
invitee.canceled: Réservation annulée -
invitee.rescheduled: Réservation replanifiée
Lister les abonnements webhook
curl -X GET "https://api.calendly.com/webhook_subscriptions?organization=https://api.calendly.com/organizations/ORG123" \
-H "Authorization: Bearer JETON_D_ACCES"
Supprimer un webhook
curl -X DELETE "https://api.calendly.com/webhook_subscriptions/ID_WEBHOOK" \
-H "Authorization: Bearer JETON_D_ACCES"
Gestion des charges utiles de webhook
Vérifier les signatures de webhook
Calendly signe chaque webhook via l’en-tête Calendly-Webhook-Signature. Pour la sécurité, vérifiez la 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('Signature invalide')
}
// Traiter le webhook
handleWebhook(req.body)
res.status(200).send('OK')
})
Traiter les événements de réservation
function handleWebhook(payload) {
const { event, payload: data } = payload
switch (event) {
case 'invitee.created':
console.log(`Nouvelle réservation : ${data.event.start_time}`)
console.log(`Invité : ${data.email}`)
// Ajouter au CRM, envoyer un e-mail, etc.
syncToCRM(data)
break
case 'invitee.canceled':
console.log(`Réservation annulée : ${data.event.uri}`)
// Mettre à jour le CRM, notifier l'équipe, etc.
removeFromCRM(data)
break
case 'invitee.rescheduled':
console.log(`Réservation reprogrammée : ${data.event.start_time}`)
// Mettre à jour l'agenda, notifier l'équipe, etc.
updateCRM(data)
break
}
}
Tester avec Apidog
L’API Calendly nécessite OAuth, ce qui complique les tests. Apidog simplifie tout le processus.
1. Simuler les réponses OAuth
Évitez de passer le flux OAuth complet à chaque test. Simulez la réponse :
{
"access_token": "jeton_d_acces_simule",
"refresh_token": "jeton_d_actualisation_simule",
"expires_in": 7200,
"created_at": 1700000000
}
2. Tester les gestionnaires de webhook
Utilisez des charges utiles simulées :
{
"created_at": "2026-03-24T10:00:00Z",
"event": "invitee.created",
"payload": {
"email": "test@exemple.com",
"name": "Utilisateur de test",
"event": {
"start_time": "2026-03-25T10:30:00Z",
"end_time": "2026-03-25T11:00:00Z",
"event_type": {
"name": "Consultation de 30 min"
}
}
}
}
Envoyez-les sur votre endpoint et vérifiez la réponse.
3. Variables d'environnement
CALENDLY_CLIENT_ID: abc123
CALENDLY_CLIENT_SECRET: xyz789
CALENDLY_ACCESS_TOKEN: jeton_enregistre
CALENDLY_REFRESH_TOKEN: actualisation_enregistree
CALENDLY_WEBHOOK_SECRET: secret_signature_webhook
4. Valider les signatures de webhook
pm.test('La signature du webhook est valide', () => {
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')
// Vérifier la signature
const valid = verifySignature(payload, signature, secret)
pm.expect(valid).to.be.true
})
Testez les webhooks Calendly gratuitement avec Apidog.
Erreurs courantes et correctifs
401 Non autorisé
Cause : Jeton invalide ou expiré.
Correctif :
- Vérifiez que le jeton n’a pas expiré (2h d’expiration)
- Rafraîchissez avec le refresh token
- L’en-tête Authorization doit être
Bearer {token}
403 Interdit
Cause : Portée OAuth insuffisante.
Correctif : Ajoutez les scopes nécessaires lors de la demande d’autorisation. Les scopes sont implicites selon ce que l’utilisateur autorise.
404 Introuvable
Cause : Ressource inexistante ou non accessible.
Correctif :
- Vérifiez l’URI
- Assurez-vous que l’utilisateur authentifié a accès
- Vérifiez la validité de l’ID d’événement ou de type d’événement
422 Entité non traitable
Cause : Erreur de validation dans la requête.
Correctif : Consultez la réponse d’erreur pour le détail :
{
"title": "Erreur de validation",
"message": "Paramètre invalide : l'URL doit être une URL HTTPS valide"
}
Alternatives et comparaisons
| Fonctionnalité | Calendly | Acuity | Cal.com | Calendly |
|---|---|---|---|---|
| Tier gratuit | Limité | Limité | Auto-hébergé gratuit | ✓ |
| Accès API | ✓ | ✓ | ✓ | ✓ |
| Webhooks | ✓ | ✓ | ✓ | ✓ |
| OAuth | ✓ | Clé API | Clé API | OAuth |
| Planification d'équipe | ✓ | ✓ | ✓ | ✓ |
| Open source | Non | Non | Oui | Non |
Calendly propose une documentation API et un flux OAuth soignés. Cal.com est l’alternative open-source avec authentification par clé API.
Cas d'utilisation réels
Intégration CRM de vente
- Création automatique de prospect dans Salesforce à chaque réservation de démo
- Notification Slack à l’équipe de vente
- Ajout du contact à la séquence marketing
- Enregistrement de l’activité dans la plateforme customer success
Plateforme de consultation
- Synchronisation des réservations avec le système interne
- Génération automatique de liens Zoom
- Envoi d’un questionnaire d’admission avant la consultation
- Création de dossier client après la réunion
Planification d’entretiens
- Mise à jour automatique de l’ATS avec les détails de l’entretien
- Notification du manager par e-mail
- Envoi d’invitations calendrier à tous les participants
- Suivi des absences pour relance
Conclusion
À retenir pour automatiser Calendly :
- Authentification OAuth 2.0 obligatoire
- API pour accéder à tous les types et événements de réservation
- Webhooks pour la notification temps réel
- Vérification de la signature webhook pour la sécurité
- Testez vos intégrations avec Apidog avant la production
Prochaines étapes :
- Créez votre application OAuth dans Calendly
- Implémentez le flux OAuth dans votre app
- Configurez un webhook
- Testez avec des charges utiles simulées dans Apidog
- Déployez en production
Testez gratuitement les webhooks Calendly avec Apidog.
FAQ
Ai-je besoin d’un forfait Calendly payant pour utiliser l’API ?
Non. L’API est disponible sur tous les forfaits, même gratuit. Les webhooks aussi. Mais certaines fonctionnalités avancées sont limitées en gratuit.
Différence entre webhooks utilisateur et organisation ?
Un webhook utilisateur ne reçoit que les événements de ce compte. Un webhook organisation couvre l’ensemble de l’équipe (privilégiez-le pour la plupart des intégrations).
Comment obtenir le secret de signature webhook ?
Lors de la création du webhook via l’API, la réponse contient signing_key. Stockez-la, elle sert à valider les signatures.
Peut-on créer des réservations via l’API ?
Non. Il n’existe pas d’endpoint pour créer des réservations : elles se font via l’UI Calendly ou les widgets. L’API est en lecture seule pour les réservations.
Comment gérer les fuseaux horaires ?
Tous les timestamps sont en UTC (ISO 8601). Convertissez en heure locale côté application. Le fuseau utilisateur est dans la ressource utilisateur.
Quelle est la limite de débit ?
Non documenté publiquement. Restez raisonnable dans vos requêtes et implémentez un backoff exponentiel si besoin.
Peut-on obtenir les réservations historiques ?
Oui, utilisez min_start_time et max_start_time pour interroger n’importe quelle période.
Comment tester OAuth localement ?
Utilisez un tunnel (ex : ngrok) pour exposer votre serveur local. Définissez l’URI de redirection sur l’URL ngrok, complétez le flux dans un navigateur, et inspectez le callback.

Top comments (0)