Webhooks
Receive real-time HTTP POST notifications when interviews are completed. Build powerful integrations and automate your hiring workflow.
Quick Start
Configure your webhook URL
Add a global URL in Settings → Global Interview Settings or set a per-interview override in the Settings tab.
Handle incoming requests
Your endpoint should return a 2xx status code within 10 seconds.
Events
interview.completedWebhooks are only sent for completed interviews that pass quality checks. Demo, failed, and abandoned interviews are excluded.
Payload
{
"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
| Field | Description |
|---|---|
event | Event type |
apiVersion | API version |
timestamp | ISO 8601 timestamp |
data.interview | Interview details & dashboard URL |
data.candidate | Candidate info, profile URL & share URL |
data.candidate.externalUserId | Your external user ID (from Smart Links) |
data.candidate.shareUrl | Public shareable link (no auth required) |
data.session | Session timing, recording & thumbnail URLs |
data.session.recordingUrl | Interview recording (audio or video) |
data.session.thumbnailUrl | Video thumbnail image (video recordings only) |
data.scores | Overall, interview & resume scores |
data.evaluation | Performance metrics & summaries |
data.resumeEvaluation | Resume evaluation (when resume uploaded) |
data.transcript | Full conversation transcript |
data.transcript[].timestamp | Unix timestamp in milliseconds |
data.transcript[].isAgent | true = AI interviewer, false = candidate |
data.transcript[].text | Message content |
Note: Optional fields like resumeEvaluation, language, and customScores are included only when applicable.
Request Headers
| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | TalentSprout-Webhooks/1.0 |
X-TalentSprout-Event | interview.completed |
X-TalentSprout-Signature | t=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— Unix timestamp when the webhook was generatedv1— HMAC-SHA256 signature of{timestamp}.{payload}
Verification Example
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.