Documentation Index
Fetch the complete documentation index at: https://docs.ropes.ai/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Ropes can send webhook notifications to your server when key events occur during the assessment lifecycle. This allows you to build automated workflows, sync data with your systems, and react to candidate progress in real-time.
Configuration
To enable webhooks, navigate to Settings → Integrations and configure:
- Webhook URL - The HTTPS endpoint where Ropes will send POST requests
- Webhook Secret - A secret key used to sign webhook payloads for verification
- Subscribed Events - Select which events you want to receive
Events
You can subscribe to any combination of the following events:
| Event | Description |
|---|
interview.sent | An assessment has been sent to a candidate |
interview.started | A candidate has started their assessment |
interview.completed | A candidate has completed their assessment |
interview.expired | An assessment has expired (with or without being started) |
Payload Structure
All webhook payloads include these base fields:
{
"event": "interview.completed",
"timestamp": "2025-11-25T14:30:00.000Z",
"interviewId": "abc123",
"email": "candidate@example.com",
"problemId": "prob_456",
"problemName": "React Dashboard Challenge"
}
Full example payloads for each specific event are below:
Event-Specific Payloads
interview.sent
{
"event": "interview.sent",
"timestamp": "2025-11-25T14:30:00.000Z",
"interviewId": "abc123",
"email": "candidate@example.com",
"problemId": "prob_456",
"problemName": "React Dashboard Challenge",
"assessmentLink": "https://yourcompany.ropes.ai/assessment/abc123",
"expiresAt": "2025-12-02T14:30:00.000Z"
}
| Field | Type | Description |
|---|
assessmentLink | string | The URL sent to the candidate |
expiresAt | string (optional) | ISO 8601 expiration date, if set |
interview.started
{
"event": "interview.started",
"timestamp": "2025-11-25T14:30:00.000Z",
"interviewId": "abc123",
"email": "candidate@example.com",
"problemId": "prob_456",
"problemName": "React Dashboard Challenge",
"startedAt": "2025-11-25T14:30:00.000Z"
}
| Field | Type | Description |
|---|
startedAt | string | ISO 8601 timestamp when the candidate started |
interview.completed
{
"event": "interview.completed",
"timestamp": "2025-01-15T10:30:00.000Z",
"interviewId": "abc123-def456-ghi789",
"email": "candidate@example.com",
"problemId": "problem-123",
"problemName": "Reverse Linked List",
"completionDate": "2025-01-15T10:30:00.000Z",
"finalScore": 85,
"plagiarism": false,
"reportLink": "https://yourorg.ropes.ai/results/abc123-def456-ghi789",
"timeTaken": 2700,
"integrationSource": "LOXO",
"externalId": "external-job-123",
"candidateExternalId": "candidate-ats-id-123"
}
| Field | Type | Description |
|---|
completionDate | string | ISO 8601 timestamp when the assessment was completed |
finalScore | number | The candidate’s final score (0-100) |
plagiarism | boolean | Whether integrity risk was flagged as high or very high |
reportLink | string | URL to view the detailed results |
timeTaken | number | Time taken in seconds |
interview.expired
{
"event": "interview.expired",
"timestamp": "2025-11-25T14:30:00.000Z",
"interviewId": "abc123",
"email": "candidate@example.com",
"problemId": "prob_456",
"problemName": "React Dashboard Challenge",
"expiredAt": "2025-11-25T14:30:00.000Z",
"wasStarted": false
}
| Field | Type | Description |
|---|
expiredAt | string | ISO 8601 timestamp when the assessment expired |
wasStarted | boolean | Whether the candidate had started the assessment before it expired |
Security
Signature Verification
Every webhook request includes an x-ropes-webhook-signature header containing an HMAC-SHA256 signature of the request body, signed with your webhook secret.
Use the following code as an example of how to conduct signature verification.
const crypto = require('crypto')
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex')
return crypto.timingSafeEquals(Buffer.from(signature), Buffer.from(expectedSignature))
}
// In your webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-ropes-webhook-signature']
if (!verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
// Process the webhook
const { event, interviewId } = req.body
console.log(`Received ${event} for interview ${interviewId}`)
res.status(200).send('OK')
})
Best Practices
- Always verify the webhook signature before processing
- Use HTTPS endpoints only
- Respond with a 2xx status code within 10 seconds
- Process webhooks asynchronously if they trigger long-running operations
- Store your webhook secret securely (e.g., environment variables)
Delivery & Retries
Ropes will attempt to deliver each webhook up to 3 times:
- Initial delivery - Immediately when the event occurs
- First retry - 1 minute after the initial failure
- Second retry - 5 minutes after the first retry
A delivery is considered successful when your endpoint returns a 2xx HTTP status code. After all retry attempts are exhausted, the delivery is marked as failed.
Timeout
Webhook requests timeout after 10 seconds. Ensure your endpoint responds quickly to avoid unnecessary retries. Clients are responsible for handling idempotency on retries.
Testing
During development, you can use tools like webhook.site or ngrok to receive webhooks locally and inspect the payloads.