# Plugin Webhook Framework

Lumi exposes a webhook service to enabled plugins as `webhooks` in their
`init` context and as `global.lumiFrameworks.webhooks`.

## Inbound Webhooks

```js
init({ webhooks }) {
  webhooks.registerInbound({
    pluginId: "example",
    endpointId: "primary",
    namespace: "example",
    slug: webhooks.generateSlug({ identifier: "alerts" }),
    handler: async ({ rawBody, rawBodyText, parsedJson }) => {
      return { status: 204 };
    }
  });
}
```

Endpoints are mounted below `/webhooks/:namespace/:slug`, accept `POST` by
default, and have a 256 KB request limit. Handlers receive the exact raw body as
a `Buffer` and UTF-8 text. Provider signature verification must use `rawBody`
or `rawBodyText`, never a re-serialized `parsedJson` object.

Use `unregisterInbound({ pluginId, endpointId })` before replacing or removing
an endpoint. `generateSlug`, `buildPublicUrl`, and
`isTimestampWithinWindow` support common endpoint and replay-protection work.

## Outbound Webhooks

```js
const result = await webhooks.sendJson({
  pluginId: "example",
  url: "https://example.test/hooks",
  payload: { event: "example" },
  timeoutMs: 10000,
  retries: 1
});
```

`send` supports strings, buffers, custom headers, methods, retries, and an
optional signing callback. Results include status, response headers, response
body text, duration, and a success flag. Query strings and authorization
headers are not written to Lumi logs.
