> ## Documentation Index
> Fetch the complete documentation index at: https://docs.relixir.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Integrate Relixir with your systems using webhooks

## Overview

Relixir sends webhooks to your configured endpoints for various events including visitor identification and CMS content changes. Use webhooks to integrate with your CRM, marketing automation, or custom systems in real-time.

<CardGroup cols={2}>
  <Card title="Visitor Identification" icon="user-check">
    Receive real-time visitor data including company enrichment, contact information, session details, traffic source attribution, and AI search detection
  </Card>

  <Card title="CMS Content Events" icon="file-text">
    Get notified when CMS content is published, updated, or deleted
  </Card>
</CardGroup>

***

## Supported Events

| Event                | Description                                                        |
| -------------------- | ------------------------------------------------------------------ |
| `visitor.identified` | A visitor is identified on your website (contact or company level) |
| `content.published`  | A CMS content item is published for the first time                 |
| `content.updated`    | A CMS content item is republished with changes                     |
| `content.deleted`    | A CMS content item is deleted                                      |

***

## Setting Up Webhooks

<Steps>
  <Step title="Configure your endpoint">
    Create an HTTPS endpoint in your application that accepts POST requests with JSON payloads.
  </Step>

  <Step title="Add webhook subscription">
    Go to **Settings** → **Visitor ID** in your Relixir dashboard and add your endpoint URL in the Webhook Subscriptions section.
  </Step>

  <Step title="Select events">
    Choose which events you want to receive. You can select multiple event types per subscription.
  </Step>

  <Step title="Test the integration">
    Verify your endpoint receives and processes webhooks correctly by triggering an event.
  </Step>
</Steps>

### Webhook Headers

Relixir sends webhooks with these headers:

| Header         | Value                 |
| -------------- | --------------------- |
| `Content-Type` | `application/json`    |
| `User-Agent`   | `Relixir-Webhook/1.0` |

***

## Visitor Identification Webhook

When a visitor is identified, Relixir sends a `visitor.identified` webhook to your configured endpoint:

### Payload Structure

```json theme={null}
{
  "event": "visitor.identified",
  "timestamp": "2025-11-07T15:11:55.835Z",
  "data": {
    "visit": {
      "id": "uuid",
      "session_id": "abc123",
      "visitor_kind": "contact",
      "captured_url": "https://example.com/features",
      "landing_path": "/",
      "referrer_url": "https://www.google.com/search?q=data+privacy",
      "ref_medium": "search",
      "came_from_ai_search": false,
      "is_paid_click": false,
      "timestamp": "2025-11-07T14:37:28.001Z",
      "ip_location": {
        "city": "Austin",
        "state": "Texas",
        "country": "United States"
      },
      "utm": {
        "source": "google",
        "medium": "cpc",
        "campaign": "brand-campaign",
        "content": "ad-variant-1"
      },
      "pages_viewed": [
        {
          "url": "https://example.com/",
          "path": "/",
          "viewed_at": "2025-11-07T14:37:28.048Z",
          "active_seconds": 85,
          "is_cms_content": false,
          "cms_content_item_id": null
        },
        {
          "url": "https://example.com/blog/post-slug",
          "path": "/blog/post-slug",
          "viewed_at": "2025-11-07T14:41:25.560Z",
          "active_seconds": 90,
          "is_cms_content": true,
          "cms_content_item_id": "uuid-of-blog-post"
        }
      ]
    },
    "company": {
      "id": "uuid",
      "domain": "acme.com",
      "name": "Acme Corp",
      "legal_name": "Acme Corporation LLC",
      "industry": "Software Development",
      "employees_range": "51-250",
      "employees_number": 125,
      "estimated_annual_revenue": "$10-$50M",
      "linkedin_handle": "company/acme-corp",
      "crunchbase_handle": "organization/acme-corp",
      "founded_year": 2015,
      "tags": ["B2B", "SaaS"],
      "tech": ["aws", "react", "postgres"],
      "location": {
        "city": "Austin",
        "state": "Texas",
        "country": "United States"
      }
    },
    "contact": {
      "id": "uuid",
      "email": "john.doe@acme.com",
      "first_name": "John",
      "last_name": "Doe",
      "title": "VP of Engineering",
      "linkedin_url": "https://www.linkedin.com/in/johndoe",
      "location": {
        "city": "Austin",
        "state": "Texas",
        "country": "United States"
      }
    }
  }
}
```

### Visitor Kinds

| Visitor Kind | Description                                               |
| ------------ | --------------------------------------------------------- |
| `contact`    | Identified visitor with contact information (email, name) |
| `company`    | Anonymous visitor identified only at company level        |

<Info>
  The `company` and `contact` objects are only included when that data is available. Anonymous visitors may only have company-level identification.
</Info>

***

## Payload Data: AI Search Detection

The `visitor.identified` webhook automatically includes AI search detection:

| AI Engine     | Detection Method                                               |
| ------------- | -------------------------------------------------------------- |
| ChatGPT       | UTM source parameter contains "chatgpt"                        |
| Perplexity AI | Referrer URL contains "perplexity.ai"                          |
| Google Gemini | Referrer URL contains "gemini.google.com" or "bard.google.com" |
| Claude AI     | Referrer URL contains "claude.ai"                              |
| Phind         | Referrer URL contains "phind.com"                              |
| You.com       | Referrer URL contains "you.com"                                |
| Bing Chat     | Referrer URL contains "bing.com/chat"                          |
| Poe           | Referrer URL contains "poe.com"                                |

<Info>
  ChatGPT is detected via UTM source parameter (e.g., `?utm_source=chatgpt`) since ChatGPT doesn't send a referrer header.
</Info>

***

## Payload Data: Traffic Classification

All traffic is classified into categories in the `ref_medium` field:

| Category      | Description                                                    |
| ------------- | -------------------------------------------------------------- |
| `ai_search`   | AI search engines (ChatGPT, Perplexity, etc.)                  |
| `paid_search` | Paid advertising (UTM medium contains "cpc", "ppc", or "paid") |
| `search`      | Organic search (Google, Bing, DuckDuckGo, etc.)                |
| `social`      | Social media (LinkedIn, Twitter/X, Facebook, Reddit, etc.)     |
| `email`       | Email campaigns (UTM medium is "email" or "newsletter")        |
| `referral`    | Other website referrals                                        |
| `direct`      | Direct traffic (no referrer)                                   |

***

## Payload Data: CMS Content Attribution

The `pages_viewed` array in the webhook identifies which pages are Relixir-managed content:

* `is_cms_content`: Boolean indicating if the page is Relixir CMS content
* `cms_content_item_id`: UUID of the Relixir content item if applicable

This enables attribution of which Relixir blogs drive traffic and engagement.

***

## CMS Content Webhooks

When CMS content is published, updated, or deleted, Relixir sends a webhook with the following payload structure:

### Payload Structure

```json theme={null}
{
  "event": "content.published",
  "timestamp": "2026-02-13T15:30:00Z",
  "data": {
    "item_id": "uuid-of-content-item",
    "slug": "my-article-slug",
    "title": "My Article Title",
    "collection_id": "uuid-of-collection",
    "organization_id": "uuid-of-organization",
    "action": "published"
  }
}
```

### CMS Event Types

| Event               | Action      | Description                           |
| ------------------- | ----------- | ------------------------------------- |
| `content.published` | `published` | First-time publish of a content item  |
| `content.updated`   | `updated`   | Republish of an existing content item |
| `content.deleted`   | `deleted`   | Content item was deleted              |

### Payload Fields

| Field             | Type          | Description                              |
| ----------------- | ------------- | ---------------------------------------- |
| `item_id`         | string (UUID) | Unique identifier of the content item    |
| `slug`            | string        | URL slug of the content item             |
| `title`           | string        | Title of the content item (may be null)  |
| `collection_id`   | string (UUID) | ID of the collection containing the item |
| `organization_id` | string (UUID) | ID of your organization                  |
| `action`          | string        | Action that triggered the webhook        |

<Info>
  CMS webhooks are triggered for all deployment modes including hosted blogs, spreadsheet deployments, and external CMS integrations.
</Info>

***

## Troubleshooting

<Accordion title="Webhooks are not arriving">
  * Verify your endpoint URL is correct and publicly accessible
  * Ensure your endpoint returns a 2xx status code within 10 seconds
  * Check your server logs for incoming POST requests
</Accordion>

<Accordion title="CMS content not being tracked">
  * Verify your blog posts are published (not drafts)
  * Check that deployment slugs match URL paths
  * Confirm `BlogSettings.blogSlugPrefix` is configured correctly
</Accordion>

<Accordion title="AI search not being detected">
  * AI search detection uses referrer URLs and UTM parameters
  * ChatGPT doesn't send a referrer, so it requires `utm_source=chatgpt` in your URLs
  * Verify UTM parameters are preserved when visitors land on your site
</Accordion>

<Accordion title="Missing company or contact data">
  * Not all visitors can be identified at the contact level
  * Some visitors only have company-level identification
  * The `company` and `contact` fields are only present when data is available
</Accordion>

***

## Webhook Delivery

Relixir uses the following delivery behavior:

| Setting      | Value                               |
| ------------ | ----------------------------------- |
| Timeout      | 10 seconds                          |
| Retries      | 3 attempts with exponential backoff |
| Content Type | `application/json`                  |

<Info>
  Your endpoint should return a 2xx status code to acknowledge receipt. Non-2xx responses (except 4xx client errors) trigger automatic retries.
</Info>

<Info>
  Need help setting up webhooks? Contact [support@relixir.ai](mailto:support@relixir.ai).
</Info>
