Skip to main content

Introduction

Les webhooks VoiceHire vous permettent de recevoir des notifications HTTP en temps réel lorsque des événements se produisent dans votre compte. Cela vous évite d’avoir à interroger constamment l’API pour détecter les changements.

Configuration

1. Accéder aux paramètres

Connectez-vous à votre tableau de bord VoiceHire et accédez à la section API, puis à l’onglet Webhooks.

2. Configurer votre endpoint

URL du webhook
string
required
L’URL HTTPS où VoiceHire enverra les notifications
Secret partagé
string
Clé secrète optionnelle pour signer les payloads (recommandé)
Événements
array
required
Sélectionnez les événements que vous souhaitez recevoir

3. Tester la configuration

Utilisez le bouton “Tester” pour envoyer un événement de test à votre endpoint.

Format des webhooks

Tous les webhooks suivent le même format JSON :
{
  "event": "campaign.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    // Données spécifiques à l'événement
  }
}

Headers HTTP

POST /votre-endpoint HTTP/1.1
Content-Type: application/json
X-VoiceHire-Event: campaign.created
X-VoiceHire-Signature: sha256=abc123... (si secret configuré)

Vérification de la signature

Si vous avez configuré un secret partagé, VoiceHire signe chaque webhook avec HMAC-SHA256 :
import hmac
import hashlib

def verify_webhook(request):
    signature = request.headers.get('X-VoiceHire-Signature')
    if not signature:
        return False
    
    # Extraire la signature (format: sha256=...)
    expected_sig = signature.split('=')[1]
    
    # Calculer la signature
    payload = request.body
    secret = 'votre_secret_partage'
    calculated_sig = hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(expected_sig, calculated_sig)

Événements disponibles

Campagnes

campaign.created

Déclenché lors de la création d’une nouvelle campagne.
{
  "event": "campaign.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "campaign_id": "abc123def456",
    "job_title": "Développeur Full Stack",
    "contract_type": "CDI",
    "candidate_link": "https://app.voicehire.io/candidate/abc123def456",
    "questions_count": 6,
    "status": "active"
  }
}

campaign.status_changed

Déclenché lorsque le statut d’une campagne change.
{
  "event": "campaign.status_changed",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "campaign_id": "abc123def456",
    "job_title": "Développeur Full Stack",
    "old_status": "active",
    "new_status": "paused"
  }
}

Candidats

candidate.added

Déclenché lorsqu’un candidat est ajouté à une campagne.
{
  "event": "candidate.added",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "campaign_id": "abc123def456",
    "candidate_id": "550e8400-e29b-41d4-a716-446655440000",
    "first_name": "Jean",
    "last_name": "Dupont",
    "email": "[email protected]",
    "phone": "0612345678",
    "call_queued": true
  }
}

candidate.sourced

Déclenché lorsqu’un candidat est sourcé via SMS.
{
  "event": "candidate.sourced",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "campaign_id": "abc123def456",
    "candidate_id": "550e8400-e29b-41d4-a716-446655440000",
    "first_name": "Marie",
    "last_name": "MARTIN",
    "phone": "0612345678",
    "sms_sent": true
  }
}

Entretiens

candidate.interview.started

Déclenché lorsqu’un entretien téléphonique commence.
{
  "event": "candidate.interview.started",
  "timestamp": "2024-01-15T14:30:00Z",
  "data": {
    "campaign_id": "abc123def456",
    "candidate_id": "550e8400-e29b-41d4-a716-446655440000",
    "first_name": "Jean",
    "last_name": "Dupont"
  }
}

candidate.interview.completed

Déclenché lorsqu’un entretien est terminé avec succès.
{
  "event": "candidate.interview.completed",
  "timestamp": "2024-01-15T14:45:00Z",
  "data": {
    "campaign_id": "abc123def456",
    "candidate_id": "550e8400-e29b-41d4-a716-446655440000",
    "first_name": "Jean",
    "last_name": "Dupont",
    "email": "[email protected]",
    "phone": "0612345678",
    "interview_score": 8.5,
    "availability": "Disponible immédiatement",
    "availability_start": "2024-02-01",
    "salary_expectation": "45000 EUR",
    "candidate_alignment": "Excellente correspondance",
    "strengths": "Expérience React, Communication excellente",
    "concerns": "Peu d'expérience en gestion d'équipe"
  }
}

candidate.interview.completed.extended

Version étendue avec les réponses détaillées (optionnel).
{
  "event": "candidate.interview.completed.extended",
  "timestamp": "2024-01-15T14:45:00Z",
  "data": {
    // Toutes les données de candidate.interview.completed plus :
    "responses": [
      {
        "question": "Quelle est votre expérience avec React?",
        "answer": "J'ai 5 ans d'expérience...",
        "score": 9,
        "explanation": "Expertise approfondie démontrée"
      }
    ]
  }
}

candidate.interview.failed

Déclenché lorsqu’un entretien échoue ou est incomplet.
{
  "event": "candidate.interview.failed",
  "timestamp": "2024-01-15T14:35:00Z",
  "data": {
    "campaign_id": "abc123def456",
    "candidate_id": "550e8400-e29b-41d4-a716-446655440000",
    "first_name": "Pierre",
    "last_name": "Durand",
    "failure_reason": "voicemail"
  }
}
Valeurs possibles pour failure_reason :
  • voicemail : Le candidat n’a pas décroché, messagerie vocale
  • no_answer : Pas de réponse du candidat
  • user_hangup : Le candidat a raccroché pendant l’entretien
  • technical_error : Erreur technique pendant le traitement

Crédits

credits.low

Déclenché lorsque vos crédits passent sous le seuil configuré (par défaut 10).
{
  "event": "credits.low",
  "timestamp": "2024-01-15T10:00:00Z",
  "data": {
    "credits_remaining": 8.5,
    "threshold": 10
  }
}

credits.depleted

Déclenché lorsque vos crédits sont épuisés.
{
  "event": "credits.depleted",
  "timestamp": "2024-01-15T15:00:00Z",
  "data": {
    "credits_remaining": 0,
    "last_campaign_id": "abc123def456"
  }
}

Bonnes pratiques

1. Répondre rapidement

Votre endpoint doit répondre avec un code 2xx dans les 5 secondes. Pour les traitements longs, répondez immédiatement et traitez en arrière-plan.

2. Idempotence

VoiceHire peut renvoyer le même webhook en cas d’échec. Utilisez l’ID unique de l’événement pour éviter les doublons.

3. Ordre des événements

Les webhooks peuvent arriver dans le désordre. Utilisez les timestamps pour reconstituer la chronologie.

4. Gestion des erreurs

Si votre endpoint retourne une erreur (4xx ou 5xx), VoiceHire retentera 3 fois avec un délai exponentiel.

5. Surveillance

Surveillez vos webhooks depuis le tableau de bord pour détecter les échecs de livraison.

Exemple d’implémentation

from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = 'votre_secret_partage'

@app.route('/webhook/voicehire', methods=['POST'])
def handle_webhook():
    # Vérifier la signature
    signature = request.headers.get('X-VoiceHire-Signature')
    if signature and WEBHOOK_SECRET:
        expected = 'sha256=' + hmac.new(
            WEBHOOK_SECRET.encode(),
            request.data,
            hashlib.sha256
        ).hexdigest()
        
        if signature != expected:
            return jsonify({'error': 'Invalid signature'}), 401
    
    # Traiter l'événement
    event_data = request.json
    event_type = event_data['event']
    
    if event_type == 'candidate.interview.completed':
        # Traiter l'entretien terminé
        candidate = event_data['data']
        print(f"Interview completed for {candidate['first_name']} {candidate['last_name']}")
        print(f"Score: {candidate['score']}")
    
    # Répondre rapidement
    return jsonify({'status': 'received'}), 200