{"openapi":"3.1.0","info":{"title":"Kestrel Public API","version":"1.0.0","description":"REST API for the Kestrel AI first-round interviewer. Authenticate with `Authorization: Bearer ksk_…` (create keys in Admin → Settings → API keys). Keys carry `read` and/or `write` scopes. Rate limit: 120 requests per minute per key. All ids are opaque strings. Declining a candidate is never possible through the API — a human clicks decline in the admin.","contact":{"name":"Kestrel","url":"https://hrapp.arimk.com"}},"servers":[{"url":"https://hrapp.arimk.com"}],"tags":[{"name":"Meta"},{"name":"Jobs"},{"name":"Candidates"},{"name":"Interviews"},{"name":"Webhooks"}],"security":[{"apiKey":[]}],"paths":{"/api/v1/me":{"get":{"summary":"Tenant and scopes for the key","operationId":"getMe","tags":["Meta"],"x-scope":"read","security":[{"apiKey":["read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/openapi.json":{"get":{"summary":"This document","operationId":"getOpenapiJson","tags":["Meta"],"x-scope":"read","security":[{"apiKey":["read"]}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/jobs":{"get":{"summary":"List jobs","operationId":"getJobs","tags":["Jobs"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["DRAFT","OPEN","PAUSED","CLOSED"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a job (status DRAFT)","operationId":"postJobs","tags":["Jobs"],"x-scope":"write","security":[{"apiKey":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobCreate"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/jobs/{id}":{"get":{"summary":"Get a job with its full config","operationId":"getJobsId","tags":["Jobs"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Change job status","operationId":"patchJobsId","tags":["Jobs"],"x-scope":"write","security":[{"apiKey":["write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobPatch"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/candidates":{"get":{"summary":"List candidates (cursor paginated, newest first)","operationId":"getCandidates","tags":["Candidates"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"job","in":"query","required":false,"description":"job id","schema":{"type":"string"}},{"name":"stage","in":"query","required":false,"schema":{"type":"string","enum":["APPLIED","INTERVIEWING","SCORED","HUMAN_REVIEW","SECOND_INTERVIEW","OFFER","HIRED","DECLINED"]}},{"name":"since","in":"query","required":false,"description":"ISO timestamp; candidates updated after","schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CandidateList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a candidate from an external source (stores the resume, starts the interview, sends the magic link)","operationId":"postCandidates","tags":["Candidates"],"x-scope":"write","security":[{"apiKey":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CandidateCreate"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Candidate"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/candidates/{id}":{"get":{"summary":"Get a candidate with latest interview summary and scorecard","operationId":"getCandidatesId","tags":["Candidates"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CandidateDetail"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/candidates/{id}/stage":{"post":{"summary":"Move a candidate to a stage (DECLINED is refused: declining is human-only)","operationId":"postCandidatesIdStage","tags":["Candidates"],"x-scope":"write","security":[{"apiKey":["write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StageChange"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Candidate"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope, or stage=DECLINED (human-only)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/candidates/{id}/tags":{"post":{"summary":"Add / remove tags","operationId":"postCandidatesIdTags","tags":["Candidates"],"x-scope":"write","security":[{"apiKey":["write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagChange"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Candidate"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/interviews/{id}":{"get":{"summary":"Interview state summary and turns (with English text)","operationId":"getInterviewsId","tags":["Interviews"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Interview"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/interviews/{id}/scorecard":{"get":{"summary":"Scorecard JSON","operationId":"getInterviewsIdScorecard","tags":["Interviews"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Scorecard"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/interviews/{id}/transcript.txt":{"get":{"summary":"Plain-text transcript (English where available)","operationId":"getInterviewsIdTranscriptTxt","tags":["Interviews"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhooks":{"get":{"summary":"List webhook subscriptions","operationId":"getWebhooks","tags":["Webhooks"],"x-scope":"read","security":[{"apiKey":["read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Subscribe (REST Hooks). Returns the signing secret once.","operationId":"postWebhooks","tags":["Webhooks"],"x-scope":"write","security":[{"apiKey":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreate"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreated"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhooks/{id}":{"delete":{"summary":"Unsubscribe","operationId":"deleteWebhooksId","tags":["Webhooks"],"x-scope":"write","security":[{"apiKey":["write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhooks/samples/{event}":{"get":{"summary":"Latest 3 payloads for an event (real deliveries, else samples) — Zapier perform_list","operationId":"getWebhooksSamplesEvent","tags":["Webhooks"],"x-scope":"read","security":[{"apiKey":["read"]}],"parameters":[{"name":"event","in":"path","required":true,"schema":{"type":"string","enum":["candidate.applied","candidate.stage_changed","candidate.declined","interview.started","interview.completed","interview.scored","meeting.scheduled","candidate.deleted"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SampleList"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhooks/test":{"post":{"summary":"Send a signed sample event to a URL or subscription now","operationId":"postWebhooksTest","tags":["Webhooks"],"x-scope":"write","security":[{"apiKey":["write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResult"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks the write scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute / key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"ksk_…","description":"API key"}},"schemas":{"Error":{"type":"object","required":["error","code"],"properties":{"error":{"type":"string"},"code":{"type":"string","enum":["unauthorized","forbidden","not_found","bad_request","rate_limited","human_only","conflict","internal"]}}},"Me":{"type":"object","properties":{"tenant":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"languages":{"type":"array","items":{"type":"string"}}}},"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write"]}}}},"rateLimit":{"type":"object","properties":{"perMinute":{"type":"integer"}}}}},"Job":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"status":{"type":"string","enum":["DRAFT","OPEN","PAUSED","CLOSED"]},"location":{"type":"string"},"languages":{"type":"array","items":{"type":"string"}},"publishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"config":{"$ref":"#/components/schemas/JobConfig"},"urls":{"type":"object","properties":{"careers":{"type":"string"},"apply":{"type":"string"}}}}},"JobList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}}},"JobConfig":{"type":"object","description":"Engine JobConfig (packages/engine/src/types.ts). Required on create: title, description, competencies[] (id, name, weight, description, rubric[5], seedQuestions[], signals[]), languages, defaultLang, country, tone.","additionalProperties":true,"required":["title","description","competencies"]},"JobCreate":{"type":"object","required":["title","config"],"properties":{"title":{"type":"string"},"slug":{"type":"string","description":"defaults to a slug of the title"},"location":{"type":"string"},"languages":{"type":"array","items":{"type":"string","enum":["en","es"]}},"config":{"$ref":"#/components/schemas/JobConfig"}}},"JobPatch":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["DRAFT","OPEN","PAUSED","CLOSED"]}}},"Candidate":{"type":"object","properties":{"id":{"type":"string"},"jobId":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":["string","null"]},"location":{"type":["string","null"]},"lang":{"type":"string"},"stage":{"type":"string","enum":["APPLIED","INTERVIEWING","SCORED","HUMAN_REVIEW","SECOND_INTERVIEW","OFFER","HIRED","DECLINED"]},"stageChangedAt":{"type":"string","format":"date-time"},"source":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"portfolioLinks":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"interviewUrl":{"type":["string","null"],"description":"magic link (only on create)"}}},"CandidateList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Candidate"}},"nextCursor":{"type":["string","null"]}}},"CandidateCreate":{"type":"object","required":["name","email","jobId"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"jobId":{"type":"string"},"resumeUrl":{"type":"string","format":"uri","description":"publicly fetchable PDF/DOCX/image up to 10 MB; downloaded into Kestrel storage"},"lang":{"type":"string","enum":["en","es"]},"location":{"type":"string"},"source":{"type":"string","default":"api"},"tags":{"type":"array","items":{"type":"string"}},"channel":{"type":"string","enum":["chat","browser_voice","phone","whatsapp_chat"],"default":"chat"},"sendMagicLink":{"type":"boolean","default":true},"externalId":{"type":"string","description":"your id for this person; stored as an ExternalRef (kind=api)"}}},"CandidateDetail":{"allOf":[{"$ref":"#/components/schemas/Candidate"},{"type":"object","properties":{"resumeFlags":{"type":"array","items":{"type":"object"}},"parsedResume":{"type":["object","null"]},"latestInterview":{"type":["object","null"],"properties":{"id":{"type":"string"},"status":{"type":"string"},"channel":{"type":"string"},"lang":{"type":"string"},"startedAt":{"type":["string","null"]},"endedAt":{"type":["string","null"]},"turnCount":{"type":"integer"},"scorecard":{"$ref":"#/components/schemas/Scorecard"}}},"decision":{"type":["object","null"]}}}]},"StageChange":{"type":"object","required":["stage"],"properties":{"stage":{"type":"string","enum":["APPLIED","INTERVIEWING","SCORED","HUMAN_REVIEW","SECOND_INTERVIEW","OFFER","HIRED"]}}},"TagChange":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string"}},"remove":{"type":"array","items":{"type":"string"}}}},"Interview":{"type":"object","properties":{"id":{"type":"string"},"candidateId":{"type":"string"},"jobId":{"type":"string"},"channel":{"type":"string"},"lang":{"type":"string"},"status":{"type":"string"},"phase":{"type":["string","null"]},"startedAt":{"type":["string","null"]},"endedAt":{"type":["string","null"]},"turnCount":{"type":"integer"},"costUsd":{"type":"number"},"consent":{"type":["object","null"]},"turns":{"type":"array","items":{"type":"object","properties":{"idx":{"type":"integer"},"role":{"type":"string","enum":["interviewer","candidate","system"]},"text":{"type":"string"},"textEn":{"type":["string","null"]},"phase":{"type":"string"},"purpose":{"type":["string","null"]},"competencyId":{"type":["string","null"]},"ts":{"type":"string"}}}}}},"Scorecard":{"type":"object","description":"Engine Scorecard (packages/engine/src/types.ts)","additionalProperties":true,"properties":{"recommendation":{"type":"string","enum":["advance","hold","decline"]},"weightedMean":{"type":"number"},"summary":{"type":"string"},"competencies":{"type":"array","items":{"type":"object"}},"strengths":{"type":"array","items":{"type":"string"}},"concerns":{"type":"array","items":{"type":"string"}},"secondInterviewQuestions":{"type":"array","items":{"type":"string"}}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["candidate.applied","candidate.stage_changed","candidate.declined","interview.started","interview.completed","interview.scored","meeting.scheduled","candidate.deleted"]}},"active":{"type":"boolean"},"failures":{"type":"integer"},"lastDeliveryAt":{"type":["string","null"]},"createdAt":{"type":"string"}}},"WebhookList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}},"WebhookCreate":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","description":"https:// endpoint (Zapier hook URL, Make webhook, your server)"},"events":{"type":"array","items":{"type":"string","enum":["candidate.applied","candidate.stage_changed","candidate.declined","interview.started","interview.completed","interview.scored","meeting.scheduled","candidate.deleted"]}},"secret":{"type":"string","description":"optional; generated when omitted"}}},"WebhookCreated":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"shown once"}}}]},"Deleted":{"type":"object","properties":{"deleted":{"type":"boolean"},"id":{"type":"string"}}},"SampleList":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string"},"tenantId":{"type":"string"},"at":{"type":"string"},"data":{"type":"object","additionalProperties":true}}}},"WebhookTest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"subscriptionId":{"type":"string"},"event":{"type":"string","enum":["candidate.applied","candidate.stage_changed","candidate.declined","interview.started","interview.completed","interview.scored","meeting.scheduled","candidate.deleted"],"default":"candidate.applied"}}},"WebhookTestResult":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":["integer","null"]},"error":{"type":["string","null"]},"durationMs":{"type":"integer"},"headers":{"type":"object","additionalProperties":{"type":"string"}}}}}},"webhooks":{"candidate.applied":{"post":{"summary":"Webhook: candidate.applied","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"candidate.applied"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}},"candidate.stage_changed":{"post":{"summary":"Webhook: candidate.stage_changed","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"candidate.stage_changed"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}},"candidate.declined":{"post":{"summary":"Webhook: candidate.declined","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"candidate.declined"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}},"interview.started":{"post":{"summary":"Webhook: interview.started","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"interview.started"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}},"interview.completed":{"post":{"summary":"Webhook: interview.completed","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"interview.completed"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}},"interview.scored":{"post":{"summary":"Webhook: interview.scored","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"interview.scored"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}},"meeting.scheduled":{"post":{"summary":"Webhook: meeting.scheduled","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"meeting.scheduled"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}},"candidate.deleted":{"post":{"summary":"Webhook: candidate.deleted","description":"POST to the subscribed URL. Headers: X-Kestrel-Event, X-Kestrel-Timestamp, X-Kestrel-Signature (sha256=HMAC-SHA256(secret, `${timestamp}.${rawBody}`)), X-Kestrel-Delivery. 5 attempts with exponential back-off; subscription is disabled after 20 consecutive failures.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","const":"candidate.deleted"},"tenantId":{"type":"string"},"at":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"2xx":{"description":"Acknowledged"}}}}}}