# Webhooks

Webhooks deliver real-time event notifications when visitors are identified. Configure a webhook endpoint in the Bullseye dashboard, and Bullseye sends an HTTP POST to your URL with visitor, company, and session data. Use webhooks to integrate with internal tools, custom CRMs, or any system that accepts HTTP callbacks.

## Plan Requirement

Webhooks are available on **Scale plans and above**. If you are on Starter, Growth, or Free Trial, upgrade to Scale to enable webhooks.

## Configuration

Webhooks are configured per organization in the Bullseye dashboard:

1. Navigate to **Settings > Integrations > Webhooks**
2. Click **Add Webhook**
3. Enter your endpoint URL (must be HTTPS)
4. Optionally set a secret for HMAC-SHA256 signature verification
5. Select the events you want to receive
6. Save the webhook

Your endpoint must respond with a 2xx status code within 30 seconds. Non-2xx responses or timeouts trigger retries.

## Event Types

| Event                | Description                                        |
| -------------------- | -------------------------------------------------- |
| `visitor.identified` | Fired when a visitor is identified on your website |

## Payload Structure

Each webhook delivery includes a JSON payload with the following structure.

### Top-Level Fields

| Field             | Type   | Description                                     |
| ----------------- | ------ | ----------------------------------------------- |
| `event`           | string | Event type (e.g., `visitor.identified`)         |
| `timestamp`       | string | ISO 8601 timestamp when the event occurred      |
| `organization_id` | string | Your Bullseye organization ID                   |
| `session_id`      | string | Unique identifier for the visitor session       |
| `visitor`         | object | Identified visitor profile data                 |
| `company`         | object | Company data associated with the visitor        |
| `session`         | object | Session metadata (pages, UTM, referrer, device) |

### Visitor Object

The `visitor` object typically includes fields such as `email`, `first_name`, `last_name`, `job_title`, `linkedin_url`, `location`, and contact identifiers.

### Company Object

The `company` object typically includes fields such as `name`, `industry`, `employee_count`, `location`, and domain information.

### Session Object

The `session` object typically includes `landing_page`, `pages_visited`, `utm_source`, `utm_medium`, `referrer`, and `device_type`.

### Example Payload

```json
{
  "event": "visitor.identified",
  "timestamp": "2025-01-15T10:30:00Z",
  "organization_id": "org_abc123",
  "session_id": "sess_xyz789",
  "visitor": {
    "email": "jane.smith@acme.com",
    "first_name": "Jane",
    "last_name": "Smith",
    "job_title": "VP of Marketing",
    "linkedin_url": "https://linkedin.com/in/janesmith",
    "location": "San Francisco, CA"
  },
  "company": {
    "name": "Acme Corp",
    "industry": "Technology",
    "employee_count": 500,
    "location": "San Francisco, CA"
  },
  "session": {
    "landing_page": "/pricing",
    "pages_visited": ["/", "/features", "/pricing"],
    "utm_source": "google",
    "utm_medium": "cpc",
    "referrer": "https://google.com",
    "device_type": "desktop"
  }
}
```

## Signature Verification

To verify that webhook deliveries come from Bullseye, use the `X-Bullseye-Signature` header. The header contains an HMAC-SHA256 signature of the raw request body using your webhook secret.

### Verification Steps

1. Read the raw request body (before any JSON parsing)
2. Compute `HMAC-SHA256(raw_body, your_webhook_secret)`
3. Encode the result as hexadecimal
4. Compare with the value in `X-Bullseye-Signature`

If the values match, the webhook is authentic. Reject requests where the signature does not match.

### Example (Pseudocode)

```
signature = request.headers["X-Bullseye-Signature"]
expected = hmac_sha256_hex(request.raw_body, webhook_secret)
if signature != expected:
  return 401  # Unauthorized
```

## Retry Behavior

If your endpoint returns a non-2xx status code or does not respond within 30 seconds, Bullseye retries the delivery:

* **Retry schedule** — Retries occur at increasing intervals (e.g., 1 minute, 5 minutes, 30 minutes)
* **Maximum retries** — Up to 3 retries per delivery
* **Idempotency** — The same payload may be delivered more than once; design your endpoint to handle duplicate events (e.g., using `session_id` as a deduplication key)

## Best Practices

* **Use HTTPS** — Webhook endpoints must use HTTPS
* **Verify the signature** — Always validate `X-Bullseye-Signature` before processing
* **Respond quickly** — Return 200 immediately and process the payload asynchronously if needed
* **Handle duplicates** — Use `session_id` or a combination of fields to deduplicate events
* **Log failures** — Monitor for 4xx/5xx responses and fix endpoint issues promptly


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bullseye.so/api-reference/webhooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
