Skip to main content

Overview

HeyMilo Webhooks allow you to receive real-time HTTP notifications when key events occur during the candidate interview lifecycle. Instead of polling the API for updates, webhooks push data to your specified endpoint as soon as an event happens — enabling seamless automation, ATS syncing, and custom workflow triggers. With webhooks, you can:
  • Get notified instantly when a candidate starts or completes an interview
  • Receive full interview reports as soon as they are generated
  • Automate downstream actions like ATS updates, email notifications, or scoring pipelines
  • Build event-driven integrations without continuous API polling

How Webhooks Work

  1. Register a webhook via the API, specifying a destination URL, the event type you want to subscribe to, and the posting (job) it applies to.
  2. HeyMilo fires an HTTP request to your URL whenever the subscribed event occurs.
  3. Your endpoint receives the payload containing all relevant event data (candidate info, interview details, scores, etc.).

Authentication

Webhook API endpoints require authentication using the X-API-KEY header, the same key used for all Public API requests.

Webhook Event Types

HeyMilo supports the following webhook event types:

Event Lifecycle

A typical candidate journey triggers events in this order:
Note: The report_available event fires after AI analysis is complete, which may occur several seconds to minutes after the interview is marked as completed.

Webhook API Endpoints

All webhook endpoints use the base URL:

1. Create Webhook

POST /create Register a new webhook to receive event notifications for a specific job posting.

Request Body

Request Schema

Example Request

Response

Response Schema


2. Get Webhook

GET /fetch/{webhook_id} Retrieve a specific webhook configuration by its ID.

Path Parameters

Example Request

Response


3. Get All Webhooks

GET /all Retrieve all webhooks for your workspace, with optional filters.

Query Parameters

Example Request

Response


4. Deactivate Webhook

POST /deactivate/{webhook_id} Deactivate an existing webhook. Deactivated webhooks will no longer receive event notifications.

Path Parameters

Example Request


Webhook Payload Schemas

When an event fires, HeyMilo sends an HTTP request to your registered URL with a JSON payload. The payload structure varies by event type. Each event type has a distinct schema — see the full payloads and field-by-field breakdowns below.

Payload: interview_started

Sent when a candidate begins an interview session.

interview_started Payload Schema

Candidate Metadata Object: Inner Metadata Object (nullable):
Note: The inner metadata object can be null if no additional ingestion context is available.

Payload: interview_completed

Sent when a candidate finishes all required steps of an interview.

interview_completed Payload Schema


Payload: report_available

Sent when the AI-generated interview report is ready. This is the most comprehensive payload, containing the full analysis data: scores, highlights, scorecard, communication evaluation, transcript, interview data model, company info, and posting info.

report_available Top-Level Schema


agentic_data Object

agentic_data.web_interview_info Object

summary Object

scorecard Object

scorecard.questions[] Object

chat_transcript[] Object

communication Object

transcript Object


interview_data_model Object

interview_data_model.details Object

workflow_status Object

workflow_status.step_by_step[] Object

state_flags Object

details.metadata Object

details.metadata.web_interview Object

company_info Object

posting_info Object


Verifying Webhook Signatures

Webhooks registered through the v2 or v4 create endpoints are signed with HMAC-SHA256, so you can confirm the request genuinely came from HeyMilo and was not altered in transit. Verification is optional — deliveries succeed whether or not you check the signature — but it is strongly recommended for any endpoint that handles candidate data.

Getting Your Signing Secret

When you register a webhook through POST /api/v2/webhooks, the create response includes a signing_secret beginning with whsec_, nested inside the data object:
POST /api/v4/webhooks returns the same object under data, alongside a top-level "object": "webhook". With either endpoint, read the secret from data.signing_secret. A few things to know about the secret:
  • It is returned only once. The signing_secret appears in the create response and is never included in get or list responses. Store it securely as soon as you receive it.
  • It cannot be retrieved or rotated. If you lose it, delete the webhook and register a new one to obtain a fresh secret.
  • Each webhook has its own secret. Registering three webhooks for three event types gives you three distinct secrets.
  • It is returned by the v2 and v4 create endpoints only. Use POST /api/v2/webhooks (Public API v2) or POST /api/v4/webhooks. The legacy POST /api/webhook/create endpoint does not return a signing secret.
  • Webhooks registered before signing was introduced have no secret. Their deliveries are sent unsigned. To start receiving signed deliveries on an existing registration, delete it and create it again.

Signature Headers

Signed deliveries carry two additional headers: What X-HeyMilo-Delivery identifies depends on the event type:
  • For interview_started, interview_completed and report_available, it is a per-event notification ID. The value stays the same across retries of that event, so you can use it as a deduplication key.
  • For candidate_shortlisted and candidate_rejected, it identifies the webhook registration rather than the individual event, so every delivery to that webhook carries the same value. Deduplicate these events on the payload instead.
Example:

How the Signature Is Computed

The signed string is the timestamp, a literal . character, and the raw request body:
To verify a delivery:
  1. Read t and v1 from the X-HeyMilo-Signature header.
  2. Concatenate t, a ., and the raw request body.
  3. Compute the HMAC-SHA256 of that string using your signing secret and hex-encode it.
  4. Compare the result against v1 using a constant-time comparison.
Always verify against the raw request body bytes, before any JSON parsing or re-serialisation. Re-encoding the JSON can reorder keys or change whitespace, which produces a different signature and causes verification to fail.

Replay Protection

The timestamp is included in the signed string so that a captured request cannot be replayed indefinitely. HeyMilo does not impose a validity window — you choose the tolerance that suits your system. A common choice is to reject any delivery whose timestamp is more than five minutes away from your current time. A timestamp check does not by itself prevent duplicate processing: a delivery that fails is retried with the same body, so the same event can arrive more than once. Deduplicate on a key derived from the payload — for example the interview or candidate identifier combined with the event type — or on X-HeyMilo-Delivery for the event types where it carries a per-event ID.

Example: Node.js / Express

Use express.raw() for the webhook route so the original body is preserved.

Example: Python / FastAPI


Setting Up Webhooks

Step 1: Prepare Your Endpoint

Your webhook endpoint must be a publicly accessible URL that can receive HTTP requests. The endpoint should:
  • Accept POST (or GET) requests
  • Return a 200 status code to acknowledge receipt
  • Process the payload asynchronously if heavy processing is required
  • Verify the X-HeyMilo-Signature header before trusting the payload — see Verifying Webhook Signatures
The examples below omit signature verification for brevity. Production endpoints should include it. Example endpoint (Node.js / Express):
Example endpoint (Python / FastAPI):

Step 2: Register the Webhook

Use the Create Webhook API to register your endpoint for the desired event type and job posting.

Step 3: Verify Delivery

After registering, trigger a test event (e.g., start an interview for a test candidate) and confirm your endpoint receives the payload. Check the response status and payload structure to ensure your integration handles the data correctly.

Multiple Webhooks Per Posting

You can register multiple webhooks for the same posting to subscribe to different event types or send events to different endpoints. Example: Subscribe to all events for a single posting

Best Practices


Common Use Cases


Error Handling

If your endpoint returns a non-200 status code, the webhook delivery is considered failed. Ensure your endpoint is reliable and returns 200 promptly.

Common Errors


Support

For webhook support and questions: