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

# Webhooks

> Receive real-time HTTP notifications when events happen in your Crevio account — orders, payments, leads, AI task runs, email, and more.

**Webhooks push events to your server the moment they happen — no polling.** You register an HTTPS endpoint, choose which events to receive, and Crevio sends a signed JSON `POST` whenever one fires.

Use them to sync data, trigger your own automations, fulfill purchases, and feed analytics — anything where your code needs to react to something happening in Crevio.

<Note>
  Webhooks notify **your** server so **your** code acts. If you instead want **Crevio's AI** to act on an event, use an event-triggered [Task](/developer/guides/tasks). See [How webhooks differ from event-triggered Tasks](#how-webhooks-differ-from-event-triggered-tasks).
</Note>

## Creating an endpoint

Create endpoints from the dashboard, via the [API](/developer/guides/api-overview), or with the [TypeScript SDK](/developer/guides/sdk).

### Via dashboard

<Steps>
  <Step title="Open Developer settings">
    In your dashboard, go to **Settings → Developer**.
  </Step>

  <Step title="Create a new endpoint">
    Click **New webhook endpoint** and enter the HTTPS URL that should receive events. (HTTP is allowed only in local development.)
  </Step>

  <Step title="Select events">
    Choose which event types to subscribe to, individually or all at once.
  </Step>

  <Step title="Save and copy the secret">
    Crevio generates a **signing secret** (prefixed `whsec_`) shown once. Copy it now — you'll use it to verify incoming requests.
  </Step>
</Steps>

### Via API

Like every Crevio endpoint, params go at the **top level** (no `{"webhook_endpoint": {...}}` wrapper). Subscribe with `enabled_events`.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.crevio.co/v1/webhook_endpoints \
      -H "Authorization: Bearer YOUR_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://example.com/webhooks/crevio",
        "status": "active",
        "enabled_events": ["order.paid", "checkout.created"]
      }'
    ```
  </Tab>

  <Tab title="SDK (TypeScript)">
    ```typescript theme={null}
    import { Crevio } from "@crevio/sdk";

    const crevio = new Crevio({ apiKeyAuth: "YOUR_API_TOKEN" });

    const endpoint = await crevio.webhookEndpoints.create({
      url: "https://example.com/webhooks/crevio",
      status: "active",
      enabledEvents: ["order.paid", "checkout.created"],
    });
    ```
  </Tab>
</Tabs>

The response includes a `secret` — returned **only on creation**:

```json theme={null}
{
  "id": "wh_abc123",
  "object": "webhook_endpoint",
  "url": "https://example.com/webhooks/crevio",
  "api_version": "v1",
  "status": "active",
  "enabled_events": ["order.paid", "checkout.created"],
  "secret": "whsec_...",
  "created_at": "2026-06-21T10:30:00Z",
  "updated_at": "2026-06-21T10:30:00Z"
}
```

<Warning>
  Copy your signing secret immediately. It's shown once on creation and cannot be retrieved later — you'll need it to verify signatures.
</Warning>

List the available event types programmatically:

```bash theme={null}
curl https://api.crevio.co/v1/webhook_endpoints/events \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

## Testing an endpoint

Send a synthetic event to any active endpoint to verify your handler:

```bash theme={null}
curl -X POST https://api.crevio.co/v1/webhook_endpoints/wh_abc123/test \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

You can also test from the dashboard: **Settings → Developer → Send test**, then pick an event type. Test deliveries include `"test": true` in the body and are **not** persisted to your delivery history.

<Tip>
  Use [webhook.site](https://webhook.site) or [ngrok](https://ngrok.com) during development to inspect payloads without standing up a server.
</Tip>

## Available events

These are the event types you can subscribe to via `enabled_events`. Each has a dedicated page under **Webhook Events** in the [API reference](/developer/api-reference/introduction) showing its exact payload.

### Commerce

| Event              | Fires when                     |
| ------------------ | ------------------------------ |
| `checkout.created` | A checkout session is created  |
| `order.created`    | An order is created            |
| `order.paid`       | An order is paid               |
| `refund.created`   | A refund is issued             |
| `refund.updated`   | A refund's status changes      |
| `invoice.created`  | An invoice is created          |
| `invoice.paid`     | An invoice is paid             |
| `invoice.past_due` | An invoice passes its due date |
| `invoice.voided`   | An invoice is voided           |

### Leads & customers

| Event                       | Fires when                                        |
| --------------------------- | ------------------------------------------------- |
| `lead.created`              | A new lead is captured                            |
| `form_submission.created`   | A form submission is received                     |
| `form_submission.confirmed` | A pending submission is confirmed (double opt-in) |
| `customer.confirmed`        | A customer confirms their email (double opt-in)   |

### Catalog

| Event             | Fires when           |
| ----------------- | -------------------- |
| `product.created` | A product is created |
| `product.updated` | A product is updated |

### AI Tasks & Jobs

| Event                  | Fires when                                         |
| ---------------------- | -------------------------------------------------- |
| `task.created`         | An AI task is created                              |
| `task_run.completed`   | A task run finishes successfully                   |
| `task_run.failed`      | A task run fails                                   |
| `task_run.needs_input` | A supervised task run is awaiting input            |
| `job.completed`        | A background job (e.g. media generation) completes |
| `job.failed`           | A background job fails                             |

### Email

| Event                      | Fires when                         |
| -------------------------- | ---------------------------------- |
| `email_message.received`   | An inbound email is received       |
| `email_message.sent`       | An email is sent                   |
| `email_message.delivered`  | An email is delivered              |
| `email_message.bounced`    | An email bounces                   |
| `email_message.complained` | A recipient marks an email as spam |
| `email_message.failed`     | An email fails to send             |

## Payload format

Every delivery is an HTTP `POST` with a JSON body in this shape:

```json theme={null}
{
  "id": "whev_abc123",
  "created_at": "2026-06-21T10:30:00Z",
  "type": "order.paid",
  "api_version": "v1",
  "data": {
    "id": "ord_xyz789",
    "object": "order",
    "email": "john@example.com",
    "created_at": "2026-06-21T10:29:55Z"
  }
}
```

| Field         | Description                                                         |
| ------------- | ------------------------------------------------------------------- |
| `id`          | Unique id for this event (`whev_…`) — use it to deduplicate         |
| `created_at`  | ISO 8601 timestamp the event was created                            |
| `type`        | The event type (e.g. `order.paid`)                                  |
| `api_version` | API version used to render the payload                              |
| `data`        | The serialized resource for the event (order, customer, invoice, …) |

The shape of `data` varies by event type — it's the serialized resource relevant to that event.

## Delivery history

Each delivered event is persisted as a **webhook event** you can inspect. List your delivery history:

```bash theme={null}
curl https://api.crevio.co/v1/webhook_events \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "whev_abc123",
      "object": "webhook_event",
      "type": "order.paid",
      "created_at": "2026-06-21T10:30:00Z"
    }
  ],
  "has_more": false
}
```

Fetch a single delivery with `GET /webhook_events/{id}`.

## Retry behavior

Crevio expects a `2xx` response within **5 seconds**. If the request fails or times out:

* The event is marked **failed**.
* Failed events are retained for **7 days**, then auto-deleted.
* Crevio does **not** auto-retry failed deliveries. Re-trigger the underlying action, or use the test feature.

### Endpoint statuses

| Status     | Meaning                       |
| ---------- | ----------------------------- |
| `active`   | Receiving events normally     |
| `inactive` | Disabled — receives no events |

Deactivate an endpoint without deleting it; reactivating resumes delivery for new events.

## Security

### Verifying signatures

Every request includes an `X-Crevio-Hmac-SHA256` header: a Base64-encoded HMAC-SHA256 of the raw request body, keyed with your signing secret. Verify it before trusting a payload.

<Steps>
  <Step title="Read the raw body">Read the request body as a raw string — do not re-serialize parsed JSON.</Step>
  <Step title="Compute the digest">HMAC-SHA256 over the raw body, keyed with your `whsec_` secret.</Step>
  <Step title="Base64-encode">Base64-encode the digest.</Step>
  <Step title="Compare">Constant-time compare against the header value.</Step>
</Steps>

<CodeGroup>
  ```javascript Node.js theme={null}
  import crypto from "crypto";

  function verifyWebhook(rawBody, signature, secret) {
    const computed = crypto
      .createHmac("sha256", secret)
      .update(rawBody)
      .digest("base64");

    return crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(computed)
    );
  }
  ```

  ```python Python theme={null}
  import hmac, hashlib, base64

  def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
      computed = base64.b64encode(
          hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
      ).decode()
      return hmac.compare_digest(computed, signature)
  ```
</CodeGroup>

<Warning>
  Always verify the signature before processing a payload. Without it, anyone could forge events to your endpoint.
</Warning>

### Best practices

* **Respond fast** — return `200` immediately, then process asynchronously to avoid timeouts.
* **Deduplicate** — use the event `id` (`whev_…`); the same event may arrive more than once.
* **Use HTTPS** — required in production.
* **Protect your secret** — store it in env vars or a secrets manager; never commit it.

## Output formats

Beyond the default JSON, Crevio can format deliveries for chat platforms:

| Format        | Use case                                  |
| ------------- | ----------------------------------------- |
| Raw (default) | Standard JSON for your own server         |
| Slack         | Pre-formatted for Slack incoming webhooks |
| Discord       | Pre-formatted for Discord webhook URLs    |

Select the format when creating or editing the endpoint.

## How webhooks differ from event-triggered Tasks

Both react to platform events, but they do different jobs:

|             | Webhook                                | Event-triggered [Task](/developer/guides/tasks) |
| ----------- | -------------------------------------- | ----------------------------------------------- |
| Who acts    | Your server / your code                | Crevio's AI agent                               |
| You provide | An HTTPS endpoint                      | A natural-language prompt                       |
| Best for    | Syncing, custom fulfillment, analytics | Autonomous follow-ups, drafting, decisions      |
| Setup       | `POST /webhook_endpoints`              | `POST /tasks` with `trigger_type: "event"`      |

The subscribable internal events (and any third-party triggers) are documented under [Events](/developer/guides/events).

## Next steps

<CardGroup cols={2}>
  <Card title="Events" icon="bolt" href="/developer/guides/events">
    Internal and third-party triggers for event Tasks.
  </Card>

  <Card title="Tasks" icon="robot" href="/developer/guides/tasks">
    Let Crevio's AI react to events on your behalf.
  </Card>

  <Card title="Autonomous outreach" icon="envelope" href="/developer/guides/recipe-autonomous-outreach">
    A worked event-triggered Task on `order.paid`.
  </Card>

  <Card title="API overview" icon="book" href="/developer/guides/api-overview">
    The full set of primitives.
  </Card>
</CardGroup>
