> For the complete documentation index, see [llms.txt](https://eventx-hq.gitbook.io/knowledge-base/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://eventx-hq.gitbook.io/knowledge-base/event-setting/integrations-and-channels/integration-of-eventx-with-1000-apps-with-webhook.md).

# Integration of EventX with 1000+ Apps with Webhook

**Objective:** Send attendee events from EventX to your own systems, CRMs, or automation tools in real time — without polling.

***

## What are Webhooks?

A webhook is a real-time notification. When something happens to an attendee in your event, EventX `POST`s a JSON payload to a URL you configure.

Use webhooks to:

* Add or update attendees in your CRM (HubSpot, Salesforce, Drupal)
* Sync attendees to mailing software (Mailchimp, SendGrid)
* Trigger automations in Zapier, Make, n8n, or your own backend — connect to 1000+ apps
* Post to Slack / Teams when someone registers or checks in

All organisers can use webhooks — no Enterprise gate. You only need access to the event (organisation member or event assignee).

***

## 1. Open Webhooks

1. Go to **<https://portal.eventx.io>** and sign in.
2. Open **My Events** and choose your event.
3. Go to **Settings > Webhooks**.

> **Note:** The Webhooks tab is inside each event’s **Settings** (`/events/:eventId/settings/webhooks`). It is a full-width page so long URLs remain readable.

***

## 2. Create a Webhook

### Step 1. Add a URL

1. Click **Create Webhook**.
2. Enter the **Webhook URL** — this is the `https` endpoint that will receive the `POST`:

* Must be `https://` (plain `http://` is rejected)
* Max 2048 characters
* Private hosts are blocked: `localhost`, `127.0.0.1`, `::1`, `10.*`, `192.168.*`, `172.16.*–31.*`, `*.local`, `*.internal`
* The same URL cannot be added twice in one event (case-insensitive) — you will see “This URL already exists” and the server returns `409 WEBHOOK_URL_DUPLICATE`

### Step 2. Select Events

Check at least one event to subscribe:

| Action               | Fires when                                               |
| -------------------- | -------------------------------------------------------- |
| `attendee-create`    | A new attendee is created (import, invite, registration) |
| `attendee-update`    | An attendee is updated (profile, ticket, custom field)   |
| `attendee-delete`    | An attendee is removed                                   |
| `attendee-check-in`  | An attendee checks in (on-site / physical session)       |
| `attendee-check-out` | An attendee checks out                                   |

Selected actions appear as chips in the table.

3. Click **Create** (Edit shows **Save**). You will see a success toast.

> **Limits:** Maximum **10 webhooks per event**. When the limit is reached a blue `Maximum 10 webhooks reached.` alert appears and the **Create Webhook** button is disabled. Duplicate URLs are rejected with `409`.

> **Display:** URLs are rendered in monospace, break inside long query strings, and show the full value on hover. Table layout is fixed (`55% URL / 20% Events / 25% Actions`).

***

## 3. Test without Your Own Server — webhook.site

You can try webhooks without writing any code:

1. Open [**https://webhook.site/**](https://webhook.site/) — your unique URL (e.g. `https://webhook.site/abc123…`) is auto-generated.
2. Click **Copy** next to **Your unique URL**.
3. Back in EventX, paste it as the **Webhook URL**, select any Events, click **Create**, then click **Test** in the row. Only the clicked row shows a spinner — other rows stay enabled.
4. Back on the **webhook.site** tab you will see a new `POST` arrive. Open it to inspect the JSON. Keep the **webhook.site** tab open **before** you click **Test**.

> **Tip:** Leave the `webhook.site` tab open before you click **Test**, otherwise you will miss the request.

***

## 4. Edit / Delete

* **Edit** — opens the same dialog pre-filled with the current URL and actions. Changing the URL is checked for duplicates. Success shows `Webhook updated.`
* **Delete** — click **Delete** and confirm `Delete this webhook?`. Success shows `Webhook deleted.` and the row disappears after the list refreshes.

***

## 5. Payload Reference

### What the Test button sends

The **Test** button sends a small sample payload to verify your endpoint:

```json
{
  "config": {
    "event_id": "test-event",
    "webhook_id": "test-webhook",
    "action": "attendee-create",
    "endpoint_url": "https://webhook.site/abc123"
  },
  "attendee": {
    "id": "test-attendee-id",
    "email": "test@example.com",
    "first_name": "Test",
    "last_name": "Attendee"
  }
}
```

A successful Test shows `Webhook test succeeded (200).` in the snackbar. A non-2xx response shows a warning `Webhook test failed (status).` — open the request on `webhook.site` to see the body. A timeout or network error after 5 seconds shows `Webhook test failed.` and the server returns `502 WEBHOOK_TEST_FAILED`.

### What a real event sends

When a real attendee event fires, the Worker dispatches via `event.webhooks` (filtered by `action`, deduplicated by `url`) to the same shape, but `attendee` is the full record:

```json
{
  "config": {
    "event_id": "<eventId>",
    "webhook_id": "<webhookId>",
    "action": "attendee-update"
  },
  "attendee": {
    "id": "…",
    "user_id": "…",
    "first_name": "…",
    "last_name": "…",
    "name": "…",
    "email": "…",
    "registration_status": "…",
    "virtual_attendance_status": "…",
    "attendance_type": "…",
    "role_tags": ["…"],
    "ticket_class_id": "…",
    "ticket_class_name": "…",
    "job_title": "…",
    "organization": "…",
    "city": "…",
    "country": "…",
    "area_code": "…",
    "contact_no": "…",
    "source": "…",
    "created_at": "…",
    "update_at": "…",
    "attended_at": "…",
    "registered_at": "…",
    "checked_in_at": "…",
    "custom_fields": { "…": "…" },
    "check_in_method": "…",
    "magic_link_url": "…",
    "first_entered_web_app_at": "…"
  }
}
```

`action` is always one of the five values above. `custom_fields` contains your registration-form custom fields.

> **Note:** Custom payload fields you added in registration forms are under `attendee.custom_fields`.

***

## 6. Limits & Security

* URL must be `https`, private hosts blocked, 2048 chars, no duplicate in one event, max 10/event.
* Worker validates with `zod` (`createWebhookSchema` / `updateWebhookSchema`) and returns `400 INVALID_PARAMS` / `409 WEBHOOK_URL_DUPLICATE` / `422 WEBHOOK_LIMIT_EXCEEDED` / `404 WEBHOOK_NOT_FOUND`.
* Delivery is server-side `POST application/json` from the Cloudflare Worker; it is not a browser call, so CORS on your endpoint does not matter. Ensure your endpoint accepts `POST` and returns `2xx`.
* History/retries are handled by the core dispatch queue (filtered and deduped by URL) — the Settings page shows the latest Test status only (with `bodySnippet` up to 500 chars for debugging).

***

## 7. Troubleshooting

| Symptom                          | Cause                          | Fix                                                                          |
| -------------------------------- | ------------------------------ | ---------------------------------------------------------------------------- |
| `Webhook test failed (404/500)`  | Your endpoint returned non-2xx | Open the request on `webhook.site` / your logs, check it accepts `POST JSON` |
| `Webhook test failed.` (timeout) | Endpoint not reachable or >5 s | Check URL, firewall, keep `webhook.site` tab open, retry Test                |
| `This URL already exists`        | Duplicate URL                  | Use a different URL or edit the existing one                                 |
| `Maximum 10 webhooks reached.`   | Limit                          | Delete an unused webhook first                                               |
| URL not saved                    | `http://` or private host      | Use a public `https://` URL                                                  |

> **Remarks:** Retrying is automatic on the server delivery queue; the **Test** button is a single immediate `POST` and does not retry.

***

## Frequently Asked Questions

### Q: Can all organisers use webhooks?

**A:** Yes. Any organisation member or event assignee can create, edit, and test webhooks from **Settings > Webhooks**. There is no plan or feature gate.

### Q: When does each action fire?

**A:** `attendee-create` on create/import/invite, `attendee-update` on any attendee update, `attendee-delete` on removal, `attendee-check-in` / `attendee-check-out` on physical check-in flows.

### Q: Do I need to add HMAC or auth headers?

**A:** Not in phase 1. The current payload has no signature. If you need signing, store the webhook URL behind a secret path (e.g. `https://example.com/hook?token=…`) until a signed header is added in a later migration.

### Q: What attendee data is sent?

**A:** The fields above: IDs, names, email, ticket, job/organisation, geo, contact, timestamps, `custom_fields`, and attendance states. No payment or order data is included.
