Webhook Events
Receive notifications when users connect, operations complete, or events occur.
Webhook Configuration
Set up webhooks in four steps:
- Go to the API Keys page in your Warm AI dashboard
- Open Settings for the relevant API key
- Enter your Webhook URL (must be HTTPS)
- Set a Webhook Secret for signature verification
Webhook Format
All webhook payloads are sent as JSON via POST to your configured URL.
Payload Structure:
{
"type": "event_type",
"timestamp": "2026-03-19T10:30:00Z",
"idempotency_key": "idem_abc123",
"data": { }
}| Field | Type | Description |
|---|---|---|
type | string | The event type identifier |
timestamp | string | ISO 8601 timestamp of the event |
idempotency_key | string | null | Correlation key if the event was triggered by an API call with one |
data | object | Event-specific payload |
Headers:
| Header | Value |
|---|---|
Content-Type | application/json |
X-WarmAI-Signature | sha256=<hmac> |
Verifying Webhook Signatures
Every webhook request includes an X-WarmAI-Signature header containing an HMAC-SHA256 signature of the raw request body, signed with your webhook secret.
Node.js Example:
import crypto from 'crypto';
function verifyWebhookSignature(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Usage in an Express handler
app.post('/webhooks/warmai', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-warmai-signature'];
const isValid = verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
console.log('Received event:', event.type);
res.status(200).send('OK');
});Always verify the signature before processing a webhook event. Use crypto.timingSafeEqual to prevent timing attacks.
Event Types
user_signup
Fired when a user creates their Warm AI account through the connect link.
{
"type": "user_signup",
"timestamp": "2026-03-19T10:30:00Z",
"data": {
"user_id": "usr_abc123",
"email": "jane@example.com"
}
}linkedin_connected
Fired when a user successfully connects their LinkedIn account via OAuth.
{
"type": "linkedin_connected",
"timestamp": "2026-03-19T10:32:00Z",
"data": {
"user_id": "usr_abc123",
"linkedin_url": "https://linkedin.com/in/janedoe",
"linkedin_name": "Jane Doe"
}
}linkedin_connection_failed
Fired when a user’s LinkedIn OAuth connection fails.
{
"type": "linkedin_connection_failed",
"timestamp": "2026-03-19T10:32:00Z",
"data": {
"user_id": "usr_abc123",
"error": "oauth_denied"
}
}settings_complete
Fired when a user completes the Setup Wizard (all 4 steps finished).
{
"type": "settings_complete",
"timestamp": "2026-03-19T10:45:00Z",
"data": {
"user_id": "usr_abc123",
"first_name": "Jane",
"last_name": "Doe",
"calendar_link": "https://calendly.com/janedoe/30min",
"cta_preference": "meeting",
"communication_style": "professional",
"message_length": "moderate",
"connection_request_with_note": true,
"product": {
"id": "prod_xyz789",
"name": "Acme CRM",
"status": "approved"
}
}
}product_approved
Fired when a user’s product is reviewed and approved.
{
"type": "product_approved",
"timestamp": "2026-03-19T11:00:00Z",
"data": {
"user_id": "usr_abc123",
"product_id": "prod_xyz789",
"product_name": "Acme CRM"
}
}progress_update
Fired as an outreach operation progresses through its pipeline stages.
{
"type": "progress_update",
"timestamp": "2026-03-19T11:05:00Z",
"idempotency_key": "idem_abc123",
"data": {
"user_id": "usr_abc123",
"prospect_url": "https://linkedin.com/in/prospect",
"status": "generating_message",
"progress": 60
}
}Use the idempotency_key in progress_update events to correlate them back to the original API request that triggered the operation.
Progress Status Reference
| Status | Progress | Description |
|---|---|---|
analysing_prospect | 10% | Analysing the prospect’s LinkedIn profile |
researching_prospect | 20% | Researching the prospect’s background |
analysing_company | 30% | Analysing the prospect’s company |
researching_company | 40% | Researching company details |
compiling_research | 50% | Compiling research results |
generating_message | 60% | Generating the outreach message |
reviewing_message | 70% | AI review of the generated message |
message_ready | 80% | Message is ready for delivery |
queued | 85% | Message is queued for sending |
sending | 90% | Message is being sent via LinkedIn |
delivered | 95% | Message delivered to LinkedIn |
sent | 100% | Operation complete |
failed | 0% | Operation failed |
cancelled | 0% | Operation was cancelled |