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

# Session webhooks

> HTTPS callbacks when API sessions start and end — for ops alerts and agent orchestration.

Register an HTTPS endpoint and Glasswarp will POST when a session starts or
ends. Use this for **ops alerts and agent orchestration** — not for driving the
PC (that's the API / MCP / SDK).

Deliveries are **best-effort** and may be missed. For billing reconciliation,
treat webhooks as a hint and reconcile against the [sessions API](/api-reference/overview)
(source of truth). Retries are not implemented yet.

## Setup

Webhook **management** (create / list / delete) uses your **console login JWT** —
same auth as API Keys in the developer console. Platform API keys (`gw_*`)
authenticate session/control calls; they **cannot** manage webhooks.

1. Open **Console → Webhooks**, or call `POST /v1/webhooks` with
   `Authorization: Bearer <console_access_token>` (the same JWT the console
   uses after you sign in).
2. Enter a public `https://` URL (private / loopback / link-local / cloud-metadata
   addresses are rejected; redirects are not followed).
3. Copy the **signing secret** shown once on create (`whsec_…`). It is stored
   server-side only and is **never** returned again on list/read — treat it like
   an API key.
4. Start a session — your endpoint should receive `session.started`, then
   `session.ended` when it closes (including idle timeout / owner kill).

Max **5** webhooks per account. Events default to both lifecycle events.

## Payload

```json theme={null}
{
  "type": "session.ended",
  "id": "delivery-id",
  "created_at": "2026-07-22T20:00:00.000Z",
  "data": {
    "session_id": "…",
    "rig_id": "…",
    "mode": "desktop",
    "status": "ended",
    "ended_reason": "client",
    "billed_minutes": 3
  }
}
```

### `ended_reason` (on `session.ended`)

| Value | Meaning |
| - | - |
| `client` | Caller ended the session (`DELETE` / SDK `end_session`) |
| `owner_kill` | Rig owner killed the session (console or host tray) |
| `idle_timeout` | No API activity for the session idle window (\~15m default) |
| `max_age` | Session hit the maximum age cap |
| `timeout` | Server-side timeout / orphan cleanup |
| `host_gone` | Host disconnected while the session was active |
| `unpaired` | Rig was unpaired mid-session |

Idle timeout is still a `session.ended` event — there is no separate
`session.reaped` event. Switch on `ended_reason=idle_timeout`.

## Headers

| Header | Meaning |
| - | - |
| `Content-Type` | `application/json` |
| `X-Glasswarp-Event` | `session.started` or `session.ended` |
| `X-Glasswarp-Delivery` | Unique delivery id (dedupe) |
| `X-Glasswarp-Timestamp` | Unix seconds when the delivery was signed |
| `X-Glasswarp-Signature` | `sha256=<hex>` — HMAC-SHA256 of `"{timestamp}.{raw_body}"` |

## Verify the signature

Reject deliveries whose timestamp is more than **5 minutes** from your clock
(replay protection).

```python theme={null}
import hmac, hashlib, time

def verify(secret: str, body: bytes, timestamp: str, signature: str, tolerance=300) -> bool:
    ts = int(timestamp)
    if abs(int(time.time()) - ts) > tolerance:
        return False
    got = signature.removeprefix("sha256=")
    signed = f"{ts}.".encode() + body
    expect = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(got, expect)
```

## Delivery behavior

* \~5s timeout; response body is capped — a slow or huge reply cannot tie up the worker.
* Failed deliveries update **last status** in the console.
* Retries are not implemented yet — poll sessions if you need a durable record.

## Related

* [Rigs and sessions](/concepts/rigs-and-sessions)
* [Safe agent sessions](/guides/safe-agent-sessions)
* [API reference](/api-reference/overview)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.