Logo StartupKit
EN

Webhook Events Reference

Payload shapes, headers, and field definitions for every webhook event.

Why It Matters

Every webhook delivery wraps event-specific data in the same envelope. This reference documents the exact payload shape for each event so you can parse and act on them confidently.

Payload Envelope

{
  "event": "application.submitted",
  "created_at": "2025-01-15T14:30:00Z",
  "data": { }
}
Field Type Description
event string The event type that triggered this delivery
created_at string ISO 8601 timestamp of when the event occurred
data object Event-specific payload (varies by event type)

Request Headers

Every webhook request includes these headers:

Header Example Description
Content-Type application/json Always JSON
X-Webhook-Event application.submitted The event type
X-Webhook-Signature a1b2c3d4... HMAC-SHA256 hex digest
X-Webhook-Timestamp 2025-01-15T14:30:00Z ISO 8601 timestamp used in signature
User-Agent Kit-Webhooks/1.0 Identifies Kit as the sender

See Webhook Security & Delivery for signature verification details.

Application Events

Events: application.submitted, application.rejected, application.rejection_reverted, application.advanced, application.stage_returned, application.withdrawn, application.offer_extended

application.stage_returned fires when a team member moves an application back to an earlier stage. It uses the same application payload as the other application events.

{
  "event": "application.submitted",
  "created_at": "2025-01-15T14:30:00Z",
  "data": {
    "id": 42,
    "candidate": {
      "id": 7,
      "name": "Jane Smith",
      "email": "[email protected]"
    },
    "job_posting": {
      "id": 3,
      "title": "Senior Engineer"
    },
    "current_stage": "Applied",
    "submitted_at": "2025-01-15T14:30:00Z",
    "rejected": false,
    "withdrawn": false,
    "offered": false
  }
}
Field Type Description
id integer Application ID
candidate.id integer Candidate ID
candidate.name string Candidate full name
candidate.email string Candidate email address
job_posting.id integer Job posting ID
job_posting.title string Job posting title
current_stage string Name of the current pipeline stage
submitted_at string | null ISO 8601 timestamp of submission
rejected boolean Whether the application has been rejected
withdrawn boolean Whether the candidate has withdrawn
offered boolean Whether an offer has been extended

Offer Events

Events: offer.accepted, offer.declined

  • offer.accepted / offer.declined: fired when an admin accepts or declines an offer
{
  "event": "offer.accepted",
  "created_at": "2025-01-20T10:00:00Z",
  "data": {
    "id": 15,
    "status": "accepted",
    "details": "Senior Engineer — $150k base",
    "extended_at": "2025-01-18T09:00:00Z",
    "expires_at": "2025-01-25T23:59:59Z",
    "accepted_at": null,
    "declined_at": null,
    "candidate": {
      "id": 7,
      "name": "Jane Smith",
      "email": "[email protected]"
    },
    "job_posting": {
      "id": 3,
      "title": "Senior Engineer"
    }
  }
}
Field Type Description
id integer Offer ID
status string One of: pending, accepted, declined, candidate_accepted, candidate_declined, expired
details string | null Offer details text
extended_at string | null When the offer was extended
expires_at string | null When the offer expires
accepted_at string | null When the offer was accepted by an admin
declined_at string | null When the offer was declined by an admin
candidate object Candidate details (same shape as application events)
job_posting object Job posting details (same shape as application events)

Interview Events

Events: interview.scheduled, interview.confirmed, interview.completed, interview.cancelled, interview.no_show, interview.no_show_reverted, interview.rebooked

interview.no_show_reverted fires when a no-show is undone. interview.rebooked fires after the old interview is closed and the candidate is invited to book a replacement. Both use the interview payload below.

{
  "event": "interview.scheduled",
  "created_at": "2025-01-16T09:00:00Z",
  "data": {
    "id": 28,
    "status": "pending",
    "scheduled_at": "2025-01-20T14:00:00Z",
    "duration_minutes": 60,
    "candidate": {
      "id": 7,
      "name": "Jane Smith",
      "email": "[email protected]"
    },
    "job_posting": {
      "id": 3,
      "title": "Senior Engineer"
    }
  }
}
Field Type Description
id integer Interview ID
status string Interview status (pending, confirmed, completed, cancelled, no_show)
scheduled_at string | null ISO 8601 timestamp of the scheduled time
duration_minutes integer Interview duration in minutes
candidate object Candidate details
job_posting object Job posting details

Code Assignment Events

Events: code_assignment.submitted, code_assignment.auto_submitted

{
  "event": "code_assignment.submitted",
  "created_at": "2025-01-22T16:45:00Z",
  "data": {
    "id": 11,
    "repo_url": "https://github.com/org/assignment-jane-smith",
    "submitted_at": "2025-01-22T16:45:00Z",
    "submitted_by": null,
    "deadline_at": "2025-01-25T23:59:59Z",
    "candidate": {
      "id": 7,
      "name": "Jane Smith",
      "email": "[email protected]"
    },
    "job_posting": {
      "id": 3,
      "title": "Senior Engineer"
    }
  }
}
Field Type Description
id integer Code submission ID
repo_url string GitHub repository URL
submitted_at string | null When the assignment was submitted
submitted_by object | null Team member (id, name) who marked the assignment submitted on the candidate’s behalf; null when the candidate submitted or the deadline auto-submitted
deadline_at string | null Assignment deadline
candidate object Candidate details
job_posting object Job posting details

Review Events

Events: review.submitted

{
  "event": "review.submitted",
  "created_at": "2025-01-23T11:00:00Z",
  "data": {
    "id": 9,
    "recommendation": "strong_yes",
    "reviewer": "Alex Johnson",
    "origin": "web",
    "candidate": {
      "id": 7,
      "name": "Jane Smith",
      "email": "[email protected]"
    },
    "job_posting": {
      "id": 3,
      "title": "Senior Engineer"
    },
    "stage": "Technical Interview"
  }
}
Field Type Description
id integer Review ID
recommendation string Reviewer’s recommendation
reviewer string Name of the reviewer
origin string How the review was submitted: web (in Kit) or mcp (filed by an AI tool through hiring_submit_review on the reviewer’s behalf, after they confirmed it)
candidate object Candidate details
job_posting object Job posting details
stage string Pipeline stage name where the review was submitted

Job Posting Events

Events: job_posting.published, job_posting.paused, job_posting.closed, job_posting.reopened

{
  "event": "job_posting.published",
  "created_at": "2025-01-10T08:00:00Z",
  "data": {
    "id": 3,
    "title": "Senior Engineer",
    "status": "published",
    "location": "Remote",
    "department": "Engineering",
    "employment_type": "full_time",
    "published_at": "2025-01-10T08:00:00Z",
    "closed_at": null,
    "public_url": "https://careers.example.com/senior-engineer"
  }
}
Field Type Description
id integer Job posting ID
title string Job title
status string Current status (published, paused, closed)
location string Job location
department string Department name
employment_type string Work arrangement (full_time, part_time, b2b, contract, or internship)
published_at string | null When the posting was published
closed_at string | null When the posting was closed
public_url string Public career portal URL for this posting

CSIRT Report Events

Events: csirt.report.submitted, csirt.report.triaged, csirt.report.validated, csirt.report.resolved, csirt.report.fix_verified, csirt.report.dismissed, csirt.report.informative, csirt.report.assessed, csirt.report.assigned, csirt.report.bounty_approved, csirt.report.paid, csirt.report.sla_breached, csirt.report.escalation_requested

These events require the CSIRT (bug bounty) add-on. The delivered events fire when the report status changes and use the report payload below.

Warning

csirt.report.assessed, csirt.report.assigned, and csirt.report.bounty_approved appear in subscription settings but are reserved and are not currently delivered. Do not build automation that depends on them.

csirt.report.dismissed means the report was rejected. csirt.report.informative means it was valid but had nothing to fix, and it may still have been paid a discretionary bonus. Don’t fold the two into one “closed” branch.

Two events fire outside status changes and carry the same payload:

  • csirt.report.sla_breached fires once when an open report passes its acknowledgment deadline (72 hours by default, set per program). A report that closes and later reopens can fire it again. Reports assessed as Informational don’t fire it.
  • csirt.report.escalation_requested fires when the researcher uses Request an update in the researcher portal. The researcher’s note is never included.
{
  "event": "csirt.report.submitted",
  "created_at": "2026-03-12T10:00:00Z",
  "data": {
    "id": "rpt_abc123",
    "vulnerability_type": "sql_injection",
    "severity_tier": "critical",
    "cvss_score": 9.8,
    "status": "submitted",
    "program_name": "Acme Security Program",
    "submitted_at": "2026-03-12T10:00:00Z"
  }
}
Field Type Description
id string Report prefix ID
vulnerability_type string Reported vulnerability category
severity_tier string | null Assessed severity tier (present once assessed)
cvss_score number | null CVSS score (present once assessed)
status string Report status at time of event
program_name string Name of the bug bounty program
submitted_at string | null When the report was submitted

Note: Report title and description are excluded from webhook payloads (encrypted at rest).

Outreach Events

Events: outreach.prospect.drafted, outreach.message.approved, outreach.message.sent, outreach.message.bounced, outreach.message.failed, outreach.message.deferred, outreach.message.delivery_unknown, outreach.message.confirmation_expired, outreach.message.delivery_resolved

These events require the Outreach addon.

outreach.prospect.drafted

Fired when the AI finishes researching a prospect and drafting an email.

{
  "event": "outreach.prospect.drafted",
  "created_at": "2026-03-12T10:00:00Z",
  "data": {
    "id": "op_abc123",
    "campaign_id": "oc_def456",
    "company_name": "Acme Corp",
    "display_name": "Jane Smith",
    "status": "drafted"
  }
}
Field Type Description
id string Prospect prefix ID
campaign_id string Campaign prefix ID
company_name string Prospect’s company name
display_name string Prospect’s display name
status string Prospect status at time of event

Note: Prospect email is excluded from webhook payloads (encrypted at rest).

outreach.message.approved / sent / bounced / failed / deferred / delivery_unknown / confirmation_expired

Fired when a message transitions to approved, sent, bounced, failed, deferred, delivery_unknown, or confirmation_expired status. A failed outcome is a known authentication, sender, content, or policy failure and opens a review for retry after remediation or closure. A deferred outcome exhausted safe retries for a known pre-submission failure. A delivery_unknown outcome means SMTP acceptance could not be proven, so Kit stopped automatic resend to avoid a duplicate. A confirmation_expired outcome means the reviewed recipient, sender identity, subject, or body changed before SMTP started; no delivery attempt began, and the current message must be reviewed and approved again.

{
  "event": "outreach.message.sent",
  "created_at": "2026-03-12T10:15:00Z",
  "data": {
    "id": "om_ghi789",
    "campaign_id": "oc_def456",
    "prospect_id": "op_abc123",
    "step_number": 1,
    "subject": "Quick question about Acme's hiring workflow",
    "status": "sent",
    "sent_at": "2026-03-12T10:15:00Z",
    "approved_at": "2026-03-12T09:30:00Z",
    "retry_count": 0,
    "last_error_code": null
  }
}
Field Type Description
id string Message prefix ID
campaign_id string Campaign prefix ID
prospect_id string Prospect prefix ID
step_number integer Sequence step number (1 = initial, 2+ = follow-ups)
subject string Email subject line
status string One of: approved, sent, bounced, failed, deferred, delivery_unknown, confirmation_expired
sent_at string | null When the email was sent
approved_at string | null When the draft was approved
retry_count integer Number of send retries attempted
last_error_code string | null Parsed SMTP or delivery status code when available; null when no attempt began

Note: Message email body is excluded from webhook payloads (encrypted at rest).

outreach.message.delivery_resolved

Fired when a member who can manage the campaign records the immutable decision that closes a delivery_unknown, deferred, or failed review. The outcome says whether Kit recorded an unknown delivery as sent, queued one explicitly authorized attempt after evidence or remediation, or closed the review without sending. delivery_attempt_id identifies the exact attempt whose evidence the decision resolved.

{
  "event": "outreach.message.delivery_resolved",
  "created_at": "2026-03-12T10:20:00Z",
  "data": {
    "id": 84,
    "message_id": "om_ghi789",
    "delivery_attempt_id": 312,
    "campaign_id": "oc_def456",
    "prospect_id": "op_abc123",
    "outcome": "confirmed_not_sent",
    "origin": "web",
    "resolved_by_id": 17,
    "resolved_at": "2026-03-12T10:20:00Z",
    "sent_at": null
  }
}
Field Type Description
id integer Delivery-resolution audit record ID
message_id string Message prefix ID
delivery_attempt_id integer Delivery attempt the decision resolves
campaign_id string Campaign prefix ID
prospect_id string Prospect prefix ID
outcome string confirmed_sent, confirmed_not_sent, retry_authorized, or closed_without_delivery
origin string Where the decision was recorded: web, mcp, or assistant
resolved_by_id integer | null User who confirmed the decision; null if that user was later erased
resolved_at string ISO 8601 decision timestamp
sent_at string | null Confirmed send time; present only for confirmed_sent

The optional operator note is encrypted at rest and excluded because it can contain recipient details copied from the sender’s mailbox.

Test Events

Events: test.ping

The test.ping event is sent when you click Send Test Ping in the webhook settings. Use it to verify endpoint connectivity and signature validation.

{
  "event": "test.ping",
  "created_at": "2025-01-15T14:30:00Z",
  "data": {}
}

Type to search...