Webhooks API

Configure webhook endpoints to receive real-time notifications when LinkedIn profiles and companies change.

Quick Reference

POST /api/v1/webhooks/configure
Configure webhook endpoint
GET /api/v1/webhooks/configuration
Get current configuration
PUT /api/v1/webhooks/configure
Update configuration
POST /api/v1/webhooks/test
Send test webhook
GET /api/v1/webhooks/deliveries
List webhook deliveries
POST /api/v1/webhooks/rotate-secret
Rotate webhook secret

Webhook Event Types

Sales Webhooks monitors and delivers the following event types:

Contact Events

Event Type Description
contact.position_changed Job title changed
contact.company_changed Moved to a new company
contact.headline_changed LinkedIn headline updated
contact.about_changed About section modified
contact.post_created New post published
contact.comment_created Commented on a post
contact.reaction_added Reacted to content

Company Events

Event Type Description
company.post_created New company post
company.description_changed Company description updated
company.employee_count_changed Employee count changed significantly

Configure Webhook Endpoint

Set up your webhook endpoint to receive change notifications. You can also configure your webhook URL directly through the Console UI under Settings → Webhooks for a more user-friendly experience.

POST /api/v1/webhooks/configure

Request Body

{
  "endpoint_url": "https://your-domain.com/webhook",  // Required: HTTPS URL
  "events": ["*"],  // Optional: Event types to receive (default: all)
  "is_active": true,  // Optional: Enable/disable webhook
  "initial_webhook": "all"  // Optional: "all", "latest", or "none"
}

Event Filtering

Specify which events to receive:

// Receive all events (default)
"events": ["*"]

// Only job changes
"events": ["contact.position_changed", "contact.company_changed"]

// Only content events
"events": ["contact.post_created", "company.post_created"]

// Specific contact events
"events": ["contact.*"]

Response

{
  "id": "whc_8Zx6Li1Ko",
  "endpoint_url": "https://your-domain.com/webhook",
  "events": ["*"],
  "secret": "whsec_verySecretKey123",  // Save this! Only shown once
  "is_active": true,
  "initial_webhook": "all",
  "created_at": "2025-01-20T10:30:00Z",
  "updated_at": "2025-01-20T10:30:00Z"
}

Important: Save the secret immediately. It's only shown once and is required for webhook signature verification.

Get Webhook Configuration

Retrieve your current webhook configuration.

GET /api/v1/webhooks/configuration

Response

{
  "id": "whc_8Zx6Li1Ko",
  "endpoint_url": "https://your-domain.com/webhook",
  "events": ["*"],
  "is_active": true,
  "initial_webhook": "latest",
  "created_at": "2025-01-20T10:30:00Z",
  "updated_at": "2025-01-20T10:30:00Z",
  "last_delivery_at": "2025-01-20T15:45:00Z",
  "delivery_stats": {
    "total": 1523,
    "successful": 1520,
    "failed": 3
  }
}

Note: The webhook secret is never returned in GET requests for security.

Update Webhook Configuration

Update your webhook endpoint or event subscriptions.

PUT /api/v1/webhooks/configure

Request Body

{
  "endpoint_url": "https://new-domain.com/webhook",  // Optional
  "events": ["contact.position_changed"],  // Optional
  "is_active": false  // Optional: Temporarily disable
}

Response

{
  "id": "whc_8Zx6Li1Ko",
  "endpoint_url": "https://new-domain.com/webhook",
  "events": ["contact.position_changed"],
  "is_active": false,
  "updated_at": "2025-01-20T16:00:00Z"
}

Tip: To change your webhook secret, use the rotate secret endpoint instead.

Test Webhook

Send a test event to verify your webhook endpoint is working correctly.

POST /api/v1/webhooks/test

Response

{
  "success": true,
  "webhook_id": "whc_8Zx6Li1Ko",
  "endpoint_url": "https://your-domain.com/webhook",
  "response": {
    "status": 200,
    "headers": {
      "content-type": "text/plain"
    },
    "body": "OK",
    "duration_ms": 145
  },
  "signature_header": "X-Webhook-Signature",
  "test_event": {
    "id": "evt_test_2Xk9Lm3Np",
    "type": "test",
    "created": 1705835400,
    "data": {
      "message": "This is a test webhook from Sales Webhooks"
    }
  }
}

Error Response

{
  "success": false,
  "webhook_id": "whc_8Zx6Li1Ko",
  "endpoint_url": "https://your-domain.com/webhook",
  "error": {
    "type": "connection_timeout",
    "message": "Connection timeout after 10000ms",
    "details": "Unable to connect to webhook endpoint"
  }
}

Webhook Payload Format

All webhooks follow this standard format:

{
  "id": "evt_2Xk9Lm3Np",  // Unique event ID
  "type": "contact.position_changed",  // Event type
  "created": 1705835400,  // Unix timestamp
  "data": {
    "entity": {
      "id": "sub_9Yx7Kj2Mn",  // Subscription ID
      "type": "contact",
      "linkedin_id": "jane-smith",
      "linkedin_url": "https://linkedin.com/in/jane-smith"
    },
    "changes": {
      // Event-specific data
    }
  },
  "metadata": {
    "subscription_id": "sub_9Yx7Kj2Mn",
    "sequence_number": 4567,
    "polling_timestamp": "2025-01-20T12:00:00Z",
    "retry_count": 0
  }
}

Example Payloads

Job Change Event

{
  "id": "evt_3Yk0Mn4Oq",
  "type": "contact.position_changed",
  "created": 1705835400,
  "data": {
    "entity": {
      "id": "sub_9Yx7Kj2Mn",
      "type": "contact",
      "linkedin_id": "jane-smith",
      "linkedin_url": "https://linkedin.com/in/jane-smith",
      "name": "Jane Smith"
    },
    "changes": {
      "previous_company": "Acme Corp",
      "previous_title": "Sales Manager",
      "current_company": "TechCo",
      "current_title": "VP of Sales",
      "is_promotion": false,
      "change_date": "2025-01-15"
    }
  }
}

New Post Event

{
  "id": "evt_4Zl1No5Pr",
  "type": "contact.post_created",
  "created": 1705839000,
  "data": {
    "entity": {
      "id": "sub_9Yx7Kj2Mn",
      "type": "contact",
      "linkedin_id": "john-doe",
      "name": "John Doe"
    },
    "post": {
      "id": "post_123456",
      "content": "Excited to announce our new product launch! #innovation #tech",
      "url": "https://linkedin.com/posts/john-doe_innovation-tech-123456",
      "published_at": "2025-01-20T15:30:00Z",
      "engagement": {
        "likes": 42,
        "comments": 5,
        "reposts": 2
      },
      "media_type": "text"  // or "image", "video", "document"
    }
  }
}

Webhook Request Headers

Every webhook request includes these headers:

Header Description
X-Webhook-Signature HMAC-SHA256 signature of the request body
X-Webhook-ID Unique webhook delivery ID
X-Webhook-Timestamp Unix timestamp (milliseconds)
X-Event-Type Event type (e.g., "contact.position_changed")
Content-Type Always "application/json"
User-Agent SalesWebhooks/1.0

List Webhook Deliveries

View recent webhook delivery attempts for debugging and monitoring.

GET /api/v1/webhooks/deliveries

Query Parameters

Parameter Type Description
status string Filter by: "pending", "success", "failed"
event_type string Filter by event type
limit integer Results per page (default: 20, max: 100)
offset integer Pagination offset

Response

{
  "data": [
    {
      "id": "del_5Am2Op6Qs",
      "event_id": "evt_4Zl1No5Pr",
      "event_type": "contact.post_created",
      "status": "success",
      "attempts": 1,
      "endpoint_url": "https://your-domain.com/webhook",
      "request": {
        "headers": {
          "X-Webhook-Signature": "abc123...",
          "X-Event-Type": "contact.post_created"
        },
        "body_size": 1234
      },
      "response": {
        "status": 200,
        "duration_ms": 145,
        "body": "OK"
      },
      "created_at": "2025-01-20T15:30:00Z",
      "delivered_at": "2025-01-20T15:30:00Z"
    }
  ],
  "pagination": {
    "total": 523,
    "limit": 20,
    "offset": 0
  }
}

Rotate Webhook Secret

Generate a new webhook secret for enhanced security.

POST /api/v1/webhooks/rotate-secret

Response

{
  "id": "whc_8Zx6Li1Ko",
  "new_secret": "whsec_newSecretKey456",  // Save this!
  "old_secret_valid_until": "2025-01-21T10:30:00Z",  // 24 hours
  "rotated_at": "2025-01-20T10:30:00Z"
}

Grace Period: The old secret remains valid for 24 hours to allow you to update your systems without downtime.

Webhook Delivery & Retry Policy

Delivery Requirements

  • Your endpoint must return a 2xx status code within 10 seconds
  • Response body is ignored (can be empty)
  • HTTPS is required (no HTTP endpoints)
  • Valid SSL certificate required

Retry Schedule

Failed webhooks are retried with exponential backoff:

Attempt Delay Total Time
1 Immediate 0 seconds
2 1 second 1 second
3 5 seconds 6 seconds
4 30 seconds 36 seconds

After 4 attempts, the webhook is marked as failed and won't be retried.

Webhook Best Practices

💡 Implementation Tips

  • Always verify signatures - See our security tutorial
  • Process asynchronously - Return 200 immediately, process in background
  • Handle duplicates - Use event ID for idempotency
  • Monitor failures - Check delivery logs regularly
  • Use specific event types - Don't subscribe to "*" unless needed

Next Steps

Ready to implement webhooks?