Talenval API
Integrate Talenval into your careers site, ATS, or backend. Jobs created through the API appear in your Talenval jobs board automatically.
Authentication
Every request needs an API key in the X-API-Key header (or Authorization: Bearer). Keys are per-workspace and start with sh_live_.
Generate keys in Developers.
curl -H "X-API-Key: sh_live_..." https://yafghloodzqbcjmupuwb.supabase.co/functions/v1/api/v1/jobsDrop-in SDK — connect your site in 3 lines
Paste this snippet into your company's codebase to talk to Talenval without writing any HTTP code. Keep the API key on your server and proxy browser calls through your backend.
<script src="https://smarthiring.lovable.app/talenval.js"></script>
<script>
const sh = Talenval.init({ apiKey: "sh_live_..." });
// Post a job on your careers site → it appears on Talenval automatically
await sh.jobs.create({
external_id: "req-2891",
external_source: "acme-careers",
title: "Senior Engineer",
description: "Build product features",
required_skills: ["React", "TypeScript"],
min_years_experience: 5,
company_name: "Acme",
hr_email: "hiring@acme.com",
});
</script>Node / Next.js / Deno
import Talenval from "https://smarthiring.lovable.app/talenval.js";
const sh = Talenval.init({ apiKey: process.env.TALENVAL_API_KEY });
// Mirror your whole careers board in one call (safe to re-run — deduped by external_id)
await sh.jobs.sync(myJobs.map(j => ({
external_id: j.id, external_source: "acme-careers",
title: j.title, description: j.body, required_skills: j.skills,
})));
// Application form submit
const { data: candidate } = await sh.candidates.apply({
job_id: talenvalJobId, name, email, resume_url: uploadedUrl,
});
// Move a candidate + trigger the status email/webhook
await sh.candidates.setStage(candidate.id, "interview");
// Live AI video interview link
const { data: session } = await sh.interviews.createAiSession(candidate.id);
console.log(session.interview_url);
// Receive events back
await sh.webhooks.create("https://acme.com/hooks/sh", ["candidate.stage_changed"]);Available methods: sh.jobs (list/get/create/update/remove/sync), sh.candidates (list/get/apply/setStage), sh.interviews (schedule/createAiSession/getAiSession), sh.webhooks (list/create/remove). Every method returns the same JSON shown below and throws an error carrying status and body on failure.
Jobs — auto-listing on Talenval
When a company posts a job on their careers site and calls POST /jobs, the job is inserted into their Talenval jobs board automatically. Pass external_id + external_source for safe retries — duplicate calls update the same row instead of creating a copy.
GET /jobs?limit=50— listPOST /jobs— create or upsert (dedup)GET /jobs/:id·PATCH /jobs/:id·DELETE /jobs/:id
Request
POST https://yafghloodzqbcjmupuwb.supabase.co/functions/v1/api/v1/jobs
X-API-Key: sh_live_...
Content-Type: application/json
{
"external_id": "req-2891", // your primary key — enables dedup
"external_source": "acme-careers", // your system name
"title": "Senior Engineer",
"description": "Build product features",
"requirements": "5+ years React",
"required_skills": ["React","TypeScript"],
"min_years_experience": 5,
"company_name": "Acme",
"hr_email": "hiring@acme.com",
"status": "open"
}Response 201 Created (or 200 with deduped: true)
{
"data": {
"id": "0f1c...",
"title": "Senior Engineer",
"status": "open",
"external_id": "req-2891",
"external_source": "acme-careers",
"created_at": "2026-07-12T09:12:00Z"
}
}Candidates
POST /candidates submit application · GET /candidates?job_id=… · PATCH /candidates/:id change stage (screening|interview|offer|hired|rejected) — triggers status email + webhook.
curl -X POST https://yafghloodzqbcjmupuwb.supabase.co/functions/v1/api/v1/candidates \
-H "X-API-Key: sh_live_..." -H "Content-Type: application/json" \
-d '{"job_id":"...","name":"Ada Lovelace","email":"ada@example.com","resume_url":"https://..."}'PATCH https://yafghloodzqbcjmupuwb.supabase.co/functions/v1/api/v1/candidates/{id}
{ "stage": "interview" }
// → emails candidate, fires webhook candidate.stage_changedInterviews (interactive video + AI)
The AI interview is a live video session: the candidate's camera and microphone are on, they share their screen, and the AI asks questions in audio. Camera video is used to detect the candidate leaving frame (anti-malpractice).
POST /interviews — schedule a human interview; candidate is emailed.
POST https://yafghloodzqbcjmupuwb.supabase.co/functions/v1/api/v1/interviews
{
"candidate_id": "...",
"scheduled_at": "2026-07-15T15:00:00Z",
"duration_minutes": 45,
"interview_type": "virtual",
"interviewer": "Jane Doe",
"meeting_link": "https://meet.acme.com/xyz"
}POST /interviews/ai-sessions — create a live AI video interview and get a shareable link.
POST https://yafghloodzqbcjmupuwb.supabase.co/functions/v1/api/v1/interviews/ai-sessions
{ "candidate_id": "..." }
// 201 →
{ "data": {
"id": "sess_...",
"token": "abc...",
"expires_at": "2026-07-19T09:00:00Z",
"interview_url": "https://smarthiring.lovable.app/interview/abc..."
} }GET /interviews/ai-sessions/:id — status, transcript, per-skill scores.
Webhooks
Subscribe to real-time events. Each delivery is POST JSON with headers:
X-Talenval-Event— e.g.candidate.stage_changedX-Talenval-Event-Id— unique per event (use for idempotency)X-Talenval-Signature: sha256=<hex>— HMAC-SHA256 of the raw body with your endpoint secret
Events: candidate.stage_changed, interview.scheduled, interview.ai_session_created, interview.completed, offer.created.
Deliveries retry up to 3 times with exponential backoff on 5xx or network errors; 4xx are not retried. Response bodies (first 500 chars) are stored for debugging.
POST https://yafghloodzqbcjmupuwb.supabase.co/functions/v1/api/v1/webhooks
{ "url": "https://your-app.com/hooks/sh",
"events": ["candidate.stage_changed","interview.completed"] }
// → { data: { id, url, secret: "whsec_..." } }Sample delivery
POST /hooks/sh
X-Talenval-Event: candidate.stage_changed
X-Talenval-Event-Id: 8b0c...
X-Talenval-Signature: sha256=9f2a...
{
"id": "8b0c...",
"event": "candidate.stage_changed",
"created_at": "2026-07-12T09:12:00Z",
"data": { "candidate_id": "...", "job_id": "...", "stage": "interview" }
}Verify signature (Node)
import crypto from "node:crypto";
const sig = req.headers["x-talenval-signature"].split("=")[1];
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.status(401).end();Errors
All errors return JSON { "error": "message" }.
400— validation error (missing/invalid field)401— missing or invalid API key404— resource not found or wrong version prefix410— interview link expired / session already completed429— rate limited500— internal error (retry with backoff)