API keys
Create a key per server or environment. Use a Test key while you build: it is free and never touches real candidates. Use a Live key in production.
This key is shown once. Copy it now, because you won't be able to see it again.
Your keys
- Loading keys…
No API keys yet.
Webhook
We send a POST here when a candidate finishes, so you never have to poll.
Quick reference
- Base URL
- intervue.ai/api/v1
- Create interview
- POST/interviews/
- Invite candidate
- POST/interviews/:id/candidates/
- Get result
- GET/results/:id/
- Rate limit
- 120 req/min
API reference
A REST API for adding AI interviews to any platform.
Base URL
https://intervue.ai/api/v1Authentication
Every request must include your API key in the Authorization header.
Include this header on every request:
Authorization: Bearer intv_live_xxxxxxxxxxxxxxxxxxxx
Create and revoke keys in the API keys panel at the top of this page. Keep a key secret and treat it like a password. Keys for testing start with intv_test_; see Sandbox below.
GET
/api/v1/auth/verify/
Test your API key is valid
Response — 200 OK
{
"valid": true,
"organisation": "Ecobank Ghana",
"plan": "professional",
"interviews_remaining": 83
}
Sandbox
Build and test your integration without spending credits. A key created with the
Test environment works as a sandbox: it behaves like a live key, but nothing it creates costs anything or reaches a real candidate.
Using the sandbox
Create a key with the Test environment in the API keys panel above. Test keys start with:
intv_test_xxxxxxxxxxxxxxxxxxxx
Use it exactly like a live key, on the same base URL. Switch to a live key when you go to production.
| Topic | With a test key |
|---|---|
| Credits | None used, even if your plan has no credits left. |
| Emails and WhatsApp | Nothing is sent to candidates, and no completion email is sent to you. |
| Interview links | A test candidate's link opens a sandbox page, not the interview. Test interviews can't be taken, so nothing is recorded or scored. |
| Your data | Test interviews and candidates are kept separate from your live ones. They do not appear on your Candidates page, Overview, activity feed or billing. |
| Keeping the two apart | A test key can only reach test interviews, and a live key only live ones. Using the wrong key for an ID returns 404, the same as an ID that does not exist. |
| Limits | 10 interviews and 25 candidates in any 24 hours, shared by all your test keys. |
| How long it is kept | Test interviews and their candidates are deleted after 7 days. |
GET
/api/v1/auth/verify/
Check which environment a key belongs to
Response with a test key — 200 OK
{
"valid": true,
"organisation": "Ecobank Ghana",
"plan": "professional",
"environment": "test",
"interviews_remaining": 83
}
Creating an interview or candidates with a test key
// The response includes the environment
{
"environment": "test",
"id": "...",
"title": "Senior Software Engineer"
}
When you reach a limit — 429
{
"error": "test_limit_reached",
"limit": 10,
"period": "24 hours"
}
With a test key you can create interviews, invite candidates, and list them. Test interviews can't be taken, and there is no
simulated-result option yet.
Interviews
An interview is a template — a set of questions with settings. You create one
interview per role or assessment, then invite multiple candidates to it.
POST
/api/v1/interviews/
Create a new interview
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | required | Name of the interview e.g. "Senior Engineer Assessment" |
| job_title | string | required | Role being assessed |
| questions | array | required | List of question strings. Min 1, max 12. |
| time_per_answer_minutes | integer | optional | Max minutes per answer. Default 3. Max 5. |
| deadline | date | optional | Last date candidates can complete. Format YYYY-MM-DD. |
| conversational | boolean | optional | true lets the AI interviewer ask one short follow-up after some answers. Only on plans that include it, otherwise 403 conversational_not_available. Default false. |
| fraud_detection | string | optional | basic or full. Default full. |
| identity_check | boolean | optional | Require Ghana Card ID check at session start. Default false. |
| notify_on_complete | boolean | optional | Fire webhook when each candidate completes. Default true. |
| webhook_url | string | optional | URL to receive completion events. Overrides account default. |
Example request
// POST /api/v1/interviews/
{
"title": "Senior Software Engineer",
"job_title": "Senior Software Engineer",
"questions": [
"Tell me about your experience with Python and Django",
"Describe a challenging technical problem you solved",
"How do you approach debugging a production issue?"
],
"time_per_answer_minutes": 3,
"deadline": "2026-08-30",
"fraud_detection": "full",
"identity_check": true,
"webhook_url": "https://careernovas.com/webhooks/intervue/"
}
Response — 201 Created
{
"id": "int_a1b2c3d4",
"title": "Senior Software Engineer",
"status": "active",
"questions_count": 3,
"conversational": false,
"deadline": "2026-08-30",
"created_at": "2026-07-24T14:32:00Z"
}
GET
/api/v1/interviews/{id}/
Get interview details and summary stats
Response — 200 OK
{
"id": "int_a1b2c3d4",
"title": "Senior Software Engineer",
"status": "active",
"candidates": {
"total": 48,
"completed": 31,
"pending": 17
},
"deadline": "2026-08-30"
}
Candidates
Invite candidates to an interview. Each candidate gets a unique personalised
link that only works for them.
POST
/api/v1/interviews/{id}/candidates/
Invite one candidate
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | Candidate full name |
| string | required | Candidate email — invitation sent here | |
| phone | string | optional | For WhatsApp invitation. Format: 0244123456 |
| reference | string | optional | Your internal reference e.g. "APP-001". Returned in results. |
| reference_photo_url | string | optional | URL of candidate photo from your system. Used for identity match if identity_check is enabled. |
| send_whatsapp | boolean | optional | Send WhatsApp invitation. Requires phone. Additional charge applies. |
Example request
// POST /api/v1/interviews/int_a1b2c3d4/candidates/
{
"name": "Kwame Asante",
"email": "kwame@email.com",
"phone": "0244123456",
"reference": "APP-001",
"reference_photo_url": "https://careernovas.com/photos/kwame.jpg",
"send_whatsapp": true
}
Response — 201 Created
{
"candidate_id": "cnd_x7y8z9",
"name": "Kwame Asante",
"interview_link": "https://intervue.ai/i/int_a1b2c3d4?token=cnd_x7y8z9_abc",
"status": "invited",
"invitation_sent": true,
"whatsapp_sent": true,
"expires_at": "2026-08-30T23:59:59Z"
}
POST
/api/v1/interviews/{id}/candidates/bulk/
Invite multiple candidates at once
Example request
// POST /api/v1/interviews/int_a1b2c3d4/candidates/bulk/
{
"candidates": [
{ "name": "Kwame Asante", "email": "kwame@email.com", "reference": "APP-001" },
{ "name": "Ama Boateng", "email": "ama@email.com", "reference": "APP-002" },
{ "name": "Kofi Mensah", "email": "kofi@email.com", "reference": "APP-003" }
],
"send_whatsapp": false
}
Response — 200 OK
{
"invited": 3,
"failed": 0,
"errors": [],
"candidates": [
{ "reference": "APP-001", "candidate_id": "cnd_x7y8z9", "status": "invited" },
{ "reference": "APP-002", "candidate_id": "cnd_a1b2c3", "status": "invited" },
{ "reference": "APP-003", "candidate_id": "cnd_d4e5f6", "status": "invited" }
]
}
GET
/api/v1/interviews/{id}/candidates/
List all candidates and their statuses
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | optional | How many candidates to return. Default 100, maximum 500. |
| offset | integer | optional | How many candidates to skip, for the next page. Default 0. |
Response — 200 OK
{
"environment": "live",
"interview_id": "0c1f2e9a-5b7d-4e8a-9c3b-1d2e3f4a5b6c",
"total": 48,
"completed": 31,
"pending": 17,
"limit": 100,
"offset": 0,
"candidates": [
{
"id": "7a9b3c1d-2e4f-4a6b-8c0d-1e2f3a4b5c6d",
"name": "Kwame Asante",
"email": "kwame@email.com",
"reference": "APP-001",
"status": "completed",
"invited_at": "2026-07-24T14:40:00Z",
"completed_at": "2026-07-24T16:45:00Z"
}
]
}
Candidates are listed oldest first. status is
invited,
pending or completed. Interview links are not included: they are
only returned once, in the response that creates the candidate, so store them when you receive them.Results
Retrieve the full AI-generated report for a completed interview including answer
scores, transcript, and fraud detection report.
GET
/api/v1/results/{id}/
Get full interview result
Response — 200 OK
{
"result_id": "res_p9q8r7",
"candidate_name": "Kwame Asante",
"reference": "APP-001",
"completed_at": "2026-07-24T16:45:00Z",
"overall_score": 8.4,
"integrity_score": 94,
"recommendation": "strong_candidate",
"identity_verified": true,
"answers": [
{
"question": "Tell me about your Python experience",
"transcript": "I have been working with Python for five years...",
"score": 8.8,
"feedback": "Specific and detailed with concrete examples"
}
],
"fraud_report": {
"integrity_score": 94,
"face_absent_seconds": 0,
"multiple_faces_detected": false,
"tab_switches": 1,
"phone_detected": false,
"second_voice_detected": false,
"gaze_off_screen_percent": 4.2,
"risk_level": "low"
}
}
Recommendation values
| Value | Meaning |
|---|---|
strong_candidate |
Score 8.0 and above. Recommend for next stage. |
good_candidate |
Score 6.5 to 7.9. Worth considering. |
borderline |
Score 5.0 to 6.4. Human review recommended. |
not_recommended |
Score below 5.0. |
flagged_for_review |
Integrity score below 70. Fraud suspected. |
Webhooks
Intervue sends a POST request to your webhook URL when events occur. You do not
need to poll — we push results to you automatically.
interview.completed
Fires when a candidate finishes their interview and all AI processing is complete. Usually within 3-5
minutes of the candidate submitting.
POST
{your_webhook_url}
Sent by Intervue to your server
Webhook payload
{
"event": "interview.completed",
"interview_id": "int_a1b2c3d4",
"candidate_id": "cnd_x7y8z9",
"candidate_name": "Kwame Asante",
"reference": "APP-001",
"result_id": "res_p9q8r7",
"overall_score": 8.4,
"integrity_score": 94,
"recommendation": "strong_candidate",
"result_url": "https://intervue.ai/results/res_p9q8r7",
"completed_at": "2026-07-24T16:45:00Z"
}
How to handle the webhook in Django
# CareerNovas views.py
@csrf_exempt
def intervue_webhook(request):
data = json.loads(request.body)
if data['event'] == 'interview.completed':
reference = data['reference'] # your APP-001
score = data['overall_score']
integrity = data['integrity_score']
# Update the applicant in your database
application = Application.objects.get(reference=reference)
application.interview_score = score
application.interview_integrity = integrity
application.interview_result_id = data['result_id']
application.save()
return JsonResponse({'received': true})
Always return a 200 response quickly. Do heavy processing in a background task.
Intervue retries failed webhooks 3 times over 24 hours.
Usage
Check your current usage against your plan limits.
GET
/api/v1/usage/
Current billing period usage
Response — 200 OK
{
"plan": "professional",
"interviews_included": 100,
"interviews_used": 67,
"interviews_remaining": 33,
"overage_count": 0,
"overage_charge": 0,
"period_start": "2026-07-01",
"period_end": "2026-07-31",
"next_billing_date": "2026-08-01"
}
Error codes
All errors return a JSON body with a code and message.
| HTTP status | Code | Meaning |
|---|---|---|
| 400 | invalid_request |
Missing or invalid field in request body |
| 401 | invalid_api_key |
API key missing or incorrect |
| 403 | quota_exceeded |
Monthly interview limit reached — upgrade plan |
| 404 | not_found |
Interview or candidate ID does not exist |
| 409 | already_invited |
This email is already invited to this interview |
| 429 | rate_limited |
Too many requests — slow down |
| 429 | test_limit_reached |
Test key limit reached (10 interviews or 25 candidates in 24 hours). Wait, or use a live key |
| 400 | question_limit_exceeded |
More questions than your plan allows per interview. The response includes limit, plan and the number you sent |
| 403 | conversational_not_available |
Conversational interviews are not included in your plan |
| 400 | invalid_conversational |
conversational must be true or false |
| 500 | server_error |
Something went wrong on our end — try again |
// Example error response
{
"error": {
"code": "quota_exceeded",
"message": "You have used all 100 interviews on your plan this month. Upgrade to continue.",
"upgrade_url": "https://intervue.ai/billing"
}
}