TalentSprout
API Reference

Webhooks

Receive real-time HTTP POST notifications when interviews are completed. Build powerful integrations and automate your hiring workflow.

Quick Start

1

Configure your webhook URL

Add a global URL in Settings → Global Interview Settings or set a per-interview override in the Settings tab.

2

Handle incoming requests

Your endpoint should return a 2xx status code within 10 seconds.

Events

interview.completed
Triggered when a qualified interview finishes

Webhooks are only sent for completed interviews that pass quality checks. Demo, failed, and abandoned interviews are excluded.

Payload

response.json
{
  "event": "interview.completed",
  "apiVersion": "2024-01-01",
  "timestamp": "2024-12-27T00:25:50.431Z",
  "data": {
    "interview": {
      "id": "c04f53d2",
      "title": "Senior Software Engineer",
      "companyName": "Acme Corp",
      "dashboardUrl": "https://talentsprout.ai/dashboard/interviews/c04f53d2"
    },
    "candidate": {
      "id": "6907d2602dab93276cdedb2a",
      "firstName": "John",
      "lastName": "Doe",
      "fullName": "John Doe",
      "email": "john.doe@example.com",
      "phone": "+1234567890",
      "externalUserId": "your_user_12345",
      "profileUrl": "https://talentsprout.ai/dashboard/interviews/c04f53d2/candidates/6907d2602dab93276cdedb2a",
      "shareUrl": "https://talentsprout.ai/share/interviews/c04f53d2/candidates/6907d2602dab93276cdedb2a"
    },
    "session": {
      "id": "694f268cd70bb7447a4e4d4e",
      "token": "3f54f82d...",
      "status": "completed",
      "startedAt": "2024-12-27T00:21:36.836Z",
      "completedAt": "2024-12-27T00:25:46.490Z",
      "durationMinutes": 4.16,
      "recordingUrl": "https://talentsprout.ai/media/recording/3f54f82d...",
      "thumbnailUrl": "https://talentsprout.ai/media/thumbnail/3f54f82d...",
      "resumeUrl": null
    },
    "scores": {
      "overall": 85,
      "interview": 85,
      "resume": null
    },
    "evaluation": {
      "performanceSummary": "Strong candidate with excellent communication...",
      "performance": {
        "communicationSkills": { "name": "Communication Skills", "score": 88, "notes": "..." },
        "domainExpertise": { "name": "Domain Expertise", "score": 85, "notes": "..." },
        "problemSolving": { "name": "Problem Solving", "score": 82, "notes": "..." },
        "culturalFit": { "name": "Cultural Fit", "score": 90, "notes": "..." },
        "professionalism": { "name": "Professionalism", "score": 87, "notes": "..." }
      },
      "summary": {
        "overview": "Candidate brings strong technical background...",
        "background": ["5 years experience", "Previous tech lead role"],
        "strengths": ["Strong communication", "Technical expertise"],
        "concerns": ["Limited experience with specific stack"],
        "tags": ["senior", "leadership"]
      }
    },
    "resumeEvaluation": null,
    "transcript": [
      { "timestamp": 1735263696836, "isAgent": true, "text": "Hello! Welcome..." },
      { "timestamp": 1735263702000, "isAgent": false, "text": "Thank you..." }
    ]
  }
}

Field Reference

FieldDescription
eventEvent type
apiVersionAPI version
timestampISO 8601 timestamp
data.interviewInterview details & dashboard URL
data.candidateCandidate info, profile URL & share URL
data.candidate.externalUserIdYour external user ID (from Smart Links)
data.candidate.shareUrlPublic shareable link (no auth required)
data.sessionSession timing, recording & thumbnail URLs
data.session.recordingUrlInterview recording (audio or video)
data.session.thumbnailUrlVideo thumbnail image (video recordings only)
data.scoresOverall, interview & resume scores
data.evaluationPerformance metrics & summaries
data.resumeEvaluationResume evaluation (when resume uploaded)
data.transcriptFull conversation transcript
data.transcript[].timestampUnix timestamp in milliseconds
data.transcript[].isAgenttrue = AI interviewer, false = candidate
data.transcript[].textMessage content

Note: Optional fields like resumeEvaluation, language, and customScores are included only when applicable.

Request Headers

HeaderValue
Content-Typeapplication/json
User-AgentTalentSprout-Webhooks/1.0
X-TalentSprout-Eventinterview.completed
X-TalentSprout-Signaturet=1672531200,v1=... (when enabled)

Security

Optionally verify that webhooks are sent from TalentSprout using HMAC-SHA256 signatures. Enable webhook authentication in Settings → Global Interview Settings. When disabled, webhooks are still sent but without the signature header.

Getting Your Signing Secret

  • • Your secret (starting with whsec_) is shown once when you enable authentication
  • • Copy it immediately and store it securely (e.g., environment variable)
  • • If lost, regenerate a new one — this invalidates the previous secret

Signature Format

When enabled, webhooks include the X-TalentSprout-Signature header:

t=1672531200,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
  • t — Unix timestamp when the webhook was generated
  • v1 — HMAC-SHA256 signature of {timestamp}.{payload}

Verification Example

Node.js
const crypto = require('crypto');

function verifyWebhookSignature(payload, header, secret) {
  const parts = header.split(',');
  const timestamp = parts[0].split('=')[1];
  const signature = parts[1].split('=')[1];
  
  // Reject timestamps older than 5 minutes (replay protection)
  const age = Math.floor(Date.now() / 1000) - parseInt(timestamp);
  if (age > 300) {
    throw new Error('Timestamp too old');
  }
  
  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  // Compare signatures (timing-safe)
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    throw new Error('Invalid signature');
  }
  
  return true;
}

// Usage in Express
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-talentsprout-signature'];
  
  if (signature) {
    try {
      verifyWebhookSignature(
        req.body.toString(),
        signature,
        process.env.TALENTSPROUT_WEBHOOK_SECRET
      );
    } catch (err) {
      return res.status(400).send(err.message);
    }
  }
  
  // Process the webhook
  const event = JSON.parse(req.body);
  console.log('Received:', event.event);
  
  res.status(200).send('OK');
});

Important: You must use the raw request body for signature verification. Parsing the JSON before verification will change the payload and cause signature mismatch.

Best Practices

Respond quickly

Return a 2xx status code within 10 seconds

Process async

Handle heavy operations asynchronously

Deduplicate

Use session.id to handle potential retries

Use HTTPS

Only secure endpoints are supported

Testing

Use the Send Test button in Settings → Global Interview Settings to verify your endpoint is reachable. Test events include test: true in the payload so you can identify and filter them.

To inspect the full payload structure, use webhook.site to generate a temporary endpoint.

!

Preview mode interviews do not trigger webhooks. Complete a real interview to test your integration.

Need help with your integration?

Our team is here to help you get set up.

Contact Support
    Webhooks - TalentSprout API