Skip to content

How to Send Webhooks to CarvOS

This guide explains how to send data to CarvOS via incoming webhooks from your ATS.

Overview

Instead of (or in addition to) using the REST API, your ATS can push data to CarvOS via webhooks. Both methods are processed identically — choose based on your integration pattern.

Webhooks are sent to a per-ATS endpoint:

POST /v1/webhooks/{ats_id}

Your ats_id and webhook secret are configured via the self-service portal.

Signing Your Webhooks

All webhooks to CarvOS must include an HMAC-SHA256 signature in the X-Webhook-Signature header:

import hmac
import hashlib
import json
import time

def sign_webhook(payload: dict, secret: str) -> str:
    """Generate HMAC-SHA256 signature for webhook (t={timestamp},v1={signature} format)."""
    body = json.dumps(payload, separators=(',', ':')).encode()
    timestamp = str(int(time.time()))
    signed_payload = f"{timestamp}.".encode() + body
    signature = hmac.new(
        secret.encode(),
        signed_payload,
        hashlib.sha256
    ).hexdigest()
    return f"t={timestamp},v1={signature}"

Include the signature in the X-Webhook-Signature header.

Sending a Webhook

curl -X POST "https://api.carvos.io/v1/webhooks/your-ats-id" \
  -H "X-Webhook-Signature: t=1234567890,v1=abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "event": "candidate.created",
    "event_id": "evt-unique-id",
    "client_id": "your-client-id",
    "user_id": "your-user-id",
    "candidate_id": "candidate-456",
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com"
  }'

All webhooks use a discriminated union on the event field — CarvOS routes the payload based on the event type.

Supported Incoming Events

Candidate Events

Event Trigger
candidate.created New candidate added
candidate.updated Candidate info changed
candidate.deleted Candidate removed

Vacancy Events

Event Trigger
vacancy.created New job posting
vacancy.updated Job details changed
vacancy.deleted Position closed

Application Events

Event Trigger
application.created New application submitted
application.updated Application data changed
application.deleted Application removed

Workspace Events

Event Trigger
workspace.created New workspace/tenant created
workspace.updated Workspace details changed
workspace.deleted Workspace removed
member.created New member added to workspace
member.deleted Member removed from workspace

See the API Reference for the full payload schema for each event type.

Error Handling

Status Meaning
202 Accepted for processing
400 Invalid payload
401 Invalid signature or API key
422 Validation error

Warning

Signatures older than 5 minutes are rejected to prevent replay attacks.

Next Steps