{"openapi":"3.1.0","info":{"title":"JobMojito Webhooks","version":"1.0.0","description":"Outgoing webhooks JobMojito POSTs to your configured endpoint(s) when an interview or assessment reaches a lifecycle milestone. Configure the target URL, subscribed events and custom auth headers per environment in your webhook settings. Respond with any 2xx to acknowledge; failed deliveries are retried."},"webhooks":{"interview_result":{"post":{"tags":["Webhooks"],"summary":"Interview result submitted","description":"Sent when an interview or assessment is submitted by the candidate (the result is finalized and AI-scored). If the interview is configured to generate a PDF report, this event is delayed until the report is ready so `pdf_export_url` is included. Also re-sent when a result field changes afterwards (score, recruiter decision, AI analysis, or the PDF report URL).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInterviewResultPayload"}}}},"responses":{"200":{"description":"Return any 2xx status to acknowledge receipt. Non-2xx or a timeout causes the delivery to be retried."}}}},"interview_collected":{"post":{"tags":["Webhooks"],"summary":"Interview answers collected","description":"Sent when the candidate finishes the interview and their raw answers are collected, before final AI scoring.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInterviewResultPayload"}}}},"responses":{"200":{"description":"Return any 2xx status to acknowledge receipt. Non-2xx or a timeout causes the delivery to be retried."}}}},"interview_failed":{"post":{"tags":["Webhooks"],"summary":"Interview failed","description":"Sent when an interview does not complete successfully — failed, abandoned, or terminated with no speech detected. The scoring and AI-analysis fields (score, ai_analysis*, ai_analysis_recruiter_score, recruiter decision, pdf_export_url) are typically empty/null for this event, since the interview did not complete.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInterviewResultPayload"}}}},"responses":{"200":{"description":"Return any 2xx status to acknowledge receipt. Non-2xx or a timeout causes the delivery to be retried."}}}}},"components":{"schemas":{"WebhookInterviewResultPayload":{"type":"object","properties":{"id":{"type":"string","description":"interview_result id this event is about."},"interview_id":{"type":"string","description":"Interview definition id (question_set_id)."},"question_set_id":{"type":"string","description":"Same as interview_id (the interview_def_set id)."},"status":{"type":"string","description":"Result lifecycle status (e.g. active, draft)."},"interview_status":{"type":"string","nullable":true,"description":"Coach/interview status (coach_status), e.g. completed, \"completed, stopped early\", failed, abandoned."},"processing_status":{"type":"string","nullable":true,"description":"AI processing status (e.g. completed)."},"profile_interview_id":{"type":"string","nullable":true,"description":"Candidate profile_interview id."},"profile_id":{"type":"string","nullable":true,"description":"Candidate profile id (when a registered profile is linked)."},"candidate_external_id":{"type":"string","nullable":true,"description":"Your external id for the candidate (present when a candidate is linked)."},"candidate_name":{"type":"string","nullable":true,"description":"Candidate name (present when a candidate is linked)."},"candidate_email":{"type":"string","nullable":true,"description":"Candidate email (present when a candidate is linked)."},"candidate_phone_number":{"type":"string","nullable":true,"description":"Candidate phone number (present when a candidate is linked)."},"score":{"type":"number","nullable":true,"description":"Overall interview score."},"ai_analysis_recruiter_score":{"type":"number","nullable":true,"description":"Recruiter-facing AI score (score_interview_ai)."},"ai_analysis":{"type":"string","nullable":true,"description":"Candidate-facing AI analysis."},"ai_analysis_recruiter":{"type":"string","nullable":true,"description":"Recruiter-facing AI analysis."},"ai_analysis_other":{"nullable":true,"description":"Session-level AI analyses keyed by analysis name (jsonb). `strengths_concerns`: { strengths: string[], concerns: string[] } (0-4 items each, recruiter-facing; called `hiring_reasons` with `reasons_to_hire` / `reasons_not_to_hire` inside before 2026-09-15, and rows written before then may still carry that shape). `takeaways`: { what_went_well: string[], next_steps: { text, priority: impact | quick | longterm, guidance: { kind: say | structure | length | exercise | perspective, text }, proof? }[], fixed?: string[] } (coaching / persona sessions, learner-facing; `proof` entries are { kind: quote | ai_summary | transcript_ref | document, text, ref?: { result_question_id } }; `fixed` lists the steps from the previous attempt that the learner did this time). `multi_department`: the multi-department-selection analysis. `score_rationale`: the rubric bracket of the session score and evidenced counts. `key_statement`: { quote, result_question_id }, the one verbatim quotation a recruiter would remember the candidate by (interview / persona_interview, absent when nothing distinctive was said). Further keys may be added."},"ai_analysis_recruiter_why_hire":{"nullable":true,"description":"Reasons to hire (list). Deprecated: a copy of ai_analysis_other.strengths_concerns.strengths, kept for existing integrations.","deprecated":true},"ai_analysis_recruiter_why_not_hire":{"nullable":true,"description":"Reasons not to hire (list). Deprecated: a copy of ai_analysis_other.strengths_concerns.concerns, kept for existing integrations.","deprecated":true},"recruiter_go_next_round":{"type":"boolean","nullable":true,"description":"Recruiter decision to advance the candidate to the next round."},"pdf_export_url":{"type":"string","nullable":true,"description":"URL of the generated PDF report. Provided only when the interview is configured to generate a PDF report; null otherwise."},"reason":{"type":"string","nullable":true,"description":"Which watched field(s) changed to trigger this delivery (change reason)."}},"required":["id","interview_id","question_set_id","status","interview_status","processing_status","profile_interview_id","profile_id","score","ai_analysis_recruiter_score","ai_analysis","ai_analysis_recruiter","recruiter_go_next_round","pdf_export_url","reason"],"description":"Event payload POSTed to your configured webhook URL for interview/assessment lifecycle events."}}}}