# Webhook

Outbound Webhooks send messages from a Device Agent or workflow to an external service. Configure a reusable connection once in **Settings → Webhook**, then refer to it by name when you chat with the Agent or create a workflow.

## Choose a Service

| Service | Preset behavior |
| --- | --- |
| Feishu (also supports Lark) | Formats text for a Feishu or Lark custom bot. Body timestamp HMAC signing is optional. |
| DingTalk | Formats text for a DingTalk custom bot. Query timestamp HMAC signing is optional. |
| Slack | Formats text for a Slack Incoming Webhook. |
| Discord | Formats text for a Discord Webhook. |
| Custom Webhook | Supports custom headers, a JSON body template, signing, and an optional success condition. |

Create the incoming Webhook in the destination service first. Copy its HTTPS URL and, when signing is enabled at the destination, its signing secret.

## Create and Test a Connection

1. Open **Settings → Webhook**. With no saved connection, the form opens automatically; otherwise click **New**.
2. Enter a unique, recognizable name. The Agent and workflow graph use it to identify the destination.
3. Select the service and paste its HTTPS Webhook URL.
4. If the destination requires signing, select the matching signing method and enter its secret.
5. Enter a test message and click **Save and test**.
6. Confirm that Device Agent reports a successful HTTP status and that the message arrives at the destination.

**Save and test** sends a real outbound request. Use a test destination or a clearly labeled test message when the receiving channel is shared with other users.

The connection is saved before the test is sent. If the test fails, the connection remains saved so you can edit it and try again.

![Discord Webhook](../images/docs/integrations/webhooks/en/01-discord-webhook.png)

After a successful save and test, the Discord channel receives the test message from the Webhook.

![Discord receives a Webhook message](../images/docs/integrations/webhooks/en/02-discord-delivery.png)

## Configure a Custom Webhook

Open **Advanced settings** for a Custom Webhook when the receiver does not match a preset.

| Setting | Purpose |
| --- | --- |
| Headers | A JSON object whose values are strings, such as an authorization header required by the receiver. `Connection`, `Content-Length`, `Content-Type`, `Host`, and `Transfer-Encoding` cannot be overridden. |
| Signing method | No signing, body timestamp HMAC, or query timestamp HMAC. |
| Body template | The JSON object sent to the receiver. It must contain the <code v-pre>&#123;&#123;message&#125;&#125;</code> variable and supports no other variables. |
| Success condition | Optionally compare a response value at a path such as `$.code` with an exact string, number, boolean, or `null`. Paths use `$` and dot-separated fields or numeric indexes. Leave the path empty to use the HTTP status only. |

For example:

```json
{
  "event": "device_alert",
  "text": "{{message}}"
}
```

The Agent or workflow supplies the message text. The Webhook connection inserts it into every <code v-pre>&#123;&#123;message&#125;&#125;</code> occurrence and sends the rendered JSON body.

When a success condition is configured, the receiver must return a `2xx` response with a JSON body that contains the path.

![Custom Webhook settings](../images/docs/integrations/webhooks/en/02-custom-webhook.png)

## Use a Webhook in Conversation

Enabled connections with saved credentials are available to the Agent as a built-in Webhook capability. Name the connection and the message to send:

```text
Send "Thermostat 01 is offline; please check its power and network." through the operations-alerts Webhook.
```

The Agent selects an enabled connection by name. If no connection is available, it cannot send a Webhook message.

## Use a Webhook in a Workflow

A workflow can deliver a fixed message after a device report, or allow its Agent step to decide whether a notification is needed. Configure and test the connection first, then describe the destination and message while creating the workflow:

```text
When battery_low_warning arrives and payload.soc is below 20, send "Low battery on {{deviceId}}: SOC {{payload.soc}}%." through the operations-alerts Webhook.
```

Workflow messages can use event fields such as <code v-pre>&#123;&#123;deviceId&#125;&#125;</code>, <code v-pre>&#123;&#123;eventName&#125;&#125;</code>, and <code v-pre>&#123;&#123;payload.soc&#125;&#125;</code>. The workflow renders those fields first; the resulting text becomes the Webhook connection's <code v-pre>&#123;&#123;message&#125;&#125;</code> value. See [Workflows](../usage/workflows.md#send-a-webhook) for a complete example.

A fixed Webhook action uses its selected connection; an Agent step can choose from enabled connections. Check the workflow's Run history for the HTTP status or delivery error.

## Manage Connections

- Disable a connection to stop Agent, workflow, and test deliveries without removing its configuration.
- Click **Test** on an enabled connection to send another real test message.
- When editing only the name, message body, or success condition, leave the URL empty to keep the saved credentials. Changing the service, signing method, or headers requires entering the URL again; a signed connection also requires its signing secret.
- A connection cannot be deleted while a workflow refers to it. Update or delete those workflows first.

## Security and Delivery Boundaries

- Webhook URLs must use HTTPS and cannot contain embedded credentials or a URL fragment.
- Requests are sent from the Gateway, including to private-network HTTPS addresses. Only trusted administrators should configure destinations; protect Settings and the management API with a trusted network or authenticated access layer.
- Requests always use `POST` with `Content-Type: application/json`.
- Do not expose Webhook URLs, headers, or signing secrets in screenshots, logs, or shared messages.
- Each invocation sends one JSON `POST` request. Redirects are rejected; use the final HTTPS URL when the destination returns `3xx`. The timeout is 10 seconds, and both request and response bodies are limited to 64 KiB.
- Deliveries are synchronous: they are not queued, retried automatically, or stored in a separate delivery history. Retry manually or trigger the workflow again after resolving the destination error.

## Troubleshooting

- If **Test** is unavailable, enable the connection and confirm that credentials have been saved.
- If the HTTP status is successful but the test still fails, verify the response path and expected value.
- If a workflow cannot deliver, confirm that the referenced connection is still enabled and test it from **Settings → Webhook**.
