Webhook Gateway
The Webhook Gateway lets ChatWalaʻau be driven by external events delivered as HTTP webhooks, instead of only acting from its own chat / API surfaces. It is a small, file-backed gateway with a management portal -- the same shape as the Cron Scheduler and Pipeline portals.
The first webhook source is Microsoft Graph, used to turn a Teams meeting transcript into a structured summary automatically: when a transcript becomes available, ChatWalaʻau resolves the meeting, fetches the transcript, summarizes it into a JSON with the LLM, and writes the result into the coding workspace.
The feature is opt-in and off by default. Turn it on with WEBHOOK_ENABLED=true.
What it does
Microsoft Graph change notification
-> POST /api/webhook/msgraph (validation handshake + 202 ACK)
-> verify clientState, allowlists, de-duplicate
-> create a "teams-meeting" Pipeline job
-> resolve meeting -> fetch transcript -> summarize (LLM) -> write JSON
-> done / failed (visible in the Pipeline portal with full run history)
The notification only signals that something changed; ChatWalaʻau then fetches the data from Graph (plain notifications + fetch -- no certificate management).
Managing it
Click the Webhooks icon in the sidebar footer (next to the Declarative Agents icon) to open the portal. It shows:
- Sources -- each webhook source with its enabled flag and how many notifications it has received. Toggle a source on/off.
- Receipts -- a per-source timeline of received notifications, each marked
accepted/duplicate/rejected, with the pipeline job it spawned. - Microsoft Graph subscriptions -- list / subscribe / renew / delete, plus Renew now (a one-shot renewal of everything due), Token health (checks your Graph credentials and permissions), Validate (self-tests the notification handshake), and a manual Fetch (run the meeting summary on demand for a meeting organizer plus a meeting id or join URL -- handy for testing or backfill before any subscription exists). App-only access is organizer-scoped, so the organizer (AAD object id or UPN) is required. The list shows live Graph subscriptions as well as the ones stored locally, so a subscription that exists on Graph but is missing locally (for example after a redeploy or a changed notification URL) is never hidden.
If Subscribe says "already exists"
The Teams transcript resource allows only one subscription per app in a tenant. If a subscription already exists (even one created by a previous deployment), Subscribe reports it instead of failing silently and offers to delete the existing subscription and re-subscribe. Only the subscription for that exact resource is removed; any unrelated subscriptions are left alone.
Auto-renewal schedule
The Microsoft Graph panel shows the managed auto-renewal schedule -- how often it runs
and when it runs next -- with a Create / Re-sync button that rebuilds the schedule for
your current subscriptions. If CRON_ENABLED is off, the panel warns that subscriptions
will not be auto-renewed (renew them manually with Renew now).
The same operations are available through the manage_webhook agent tool and the
/api/webhooks/* REST API. Mutating endpoints require authentication (loopback is
exempt).
Dedicated (user-delegated) lane -- no service principal needed
Some organizations will not grant an app-only Application permission or set up the
Teams Application Access Policy that the automatic lane needs. For those cases the
Microsoft Graph source detail also offers a Dedicated fetch panel: a signed-in user
summarizes a meeting they organized by signing in with their own account via a
device code (open microsoft.com/devicelogin, enter the shown code).
- No app-only permission, no Application Access Policy. Graph access is user-scoped
(
/me/onlineMeetings), so it is naturally limited to your own meetings. - No new setting and no client secret. It reuses
GRAPH_CLIENT_ID+GRAPH_TENANT_IDfor a public-client device-code sign-in; you add a delegatedOnlineMeetingTranscript.Read.All+OnlineMeetings.Readconsent and enable "Allow public client flows" on the same app registration. - Nothing is stored. The sign-in token is used for that single run and discarded -- no refresh token, nothing written to disk.
- Organizer-scoped. You can summarize meetings you organized; a meeting you only attended cannot be retrieved (a Microsoft Graph limitation). For unattended, event-driven summarization across organizers, use the automatic (app-only) lane above.
This lane is manual and interactive (it needs a human sign-in), so it runs from the portal
only -- not from the manage_webhook agent tool. The full operator steps are in the
"Dedicated (User-Delegated) Teams Meeting Setup" guide that ships with the product.
Subscriptions expire -- keep them renewed
Microsoft Graph subscriptions have a resource-dependent maximum lifetime and stop
delivering when they lapse. Renewal is consolidated into the Cron Scheduler: while you
have at least one subscription, ChatWalaʻau keeps a managed, protected Cron job
(webhook / "Renew Microsoft Graph webhook subscriptions...") that renews due
subscriptions before they expire. The job is created on your first Subscribe and
removed when you delete the last subscription. It is visible in the Cron portal
but cannot be deleted there (it is owned by the webhook feature), and it is also
surfaced in the Webhooks portal's Auto-renewal schedule section where you can
Create / Re-sync it. Because it is a Cron job, it runs only while CRON_ENABLED is
on -- for unattended operation set CRON_ENABLED=true. Otherwise renew manually from the
Webhooks portal (Renew now / per-subscription Renew) or via the agent tool. Graph
also sends lifecycle events (reauthorizationRequired / subscriptionRemoved), which the
gateway handles automatically.
Setup order
Microsoft Graph access uses dedicated app-only credentials (the GRAPH_* variables),
separate from the Teams bot credentials. The recommended order is:
- Graph credentials -- set
GRAPH_TENANT_ID/GRAPH_CLIENT_ID/GRAPH_CLIENT_SECRET, then check Token health. - Webhook listener -- set
MSGRAPH_WEBHOOK_CLIENT_STATE,MSGRAPH_WEBHOOK_NOTIFICATION_URL(a public, tunnel-reachable URL), andMSGRAPH_WEBHOOK_RESOURCE, then run Validate. - Teams pipeline -- run a manual Fetch for a known meeting to confirm the summary pipeline end-to-end.
- Teams delivery -- Subscribe so live notifications flow.
Full operator steps -- the Graph app registration, the Teams Application Access Policy required for transcript access, and the tunnel -- are in the setup guide that ships with the product.
Security
The public ingress (/api/webhook/{source}) is the only endpoint not behind the API key
/ session cookie -- Microsoft Graph is not an API key holder. It is protected by the
Graph validation handshake, a constant-time clientState comparison, optional source
CIDR and resource allowlists, and de-duplication. The webhook management API
is authenticated like every other write endpoint.
Configuration reference
| Variable | Default | Description |
|---|---|---|
WEBHOOK_ENABLED | false | Master switch for the whole feature. |
WEBHOOK_INGRESS_BASE_PATH | /api/webhook | Base path; sources mount at <base>/{source}. |
WEBHOOK_STORE_DIR | .webhooks | Per-source state, receipts, and subscriptions. |
WEBHOOK_RECEIPT_MAX_BYTES | 1048576 | Cap per captured receipt body (0 = unbounded). |
MSGRAPH_WEBHOOK_CLIENT_STATE | (empty) | Shared secret validating Graph notifications. |
MSGRAPH_WEBHOOK_NOTIFICATION_URL | (empty) | Public URL given to Graph at subscribe time. |
MSGRAPH_WEBHOOK_RESOURCE | (empty) | Graph resource to subscribe. |
MSGRAPH_SUBSCRIPTION_RENEW_HOURS | 12 | Renewal interval (must be shorter than the resource max expiry). |
MSGRAPH_WEBHOOK_ALLOWED_CIDRS | (empty) | Optional source CIDR allowlist. |
MSGRAPH_WEBHOOK_ALLOWED_RESOURCES | (empty) | Optional resource allowlist. |
GRAPH_TENANT_ID / GRAPH_CLIENT_ID / GRAPH_CLIENT_SECRET | (empty) | Graph app-only credentials. |
GRAPH_BASE_URL | https://graph.microsoft.com/v1.0 | Optional Graph base URL override. |
TEAMS_MEETING_OUTPUT_DIR | meeting-summaries | Output subdir in the coding workspace. |
The meeting-summary model is assigned in the Model Offering Catalog under Model
Settings -> Task model assignments (roles.meeting_summary, or chatwalaau models role set meeting_summary <offering-id>); leave it unset to use the default model. The dedicated
TEAMS_MEETING_SUMMARY_MODEL variable was removed in v0.109.0.
Subscription auto-renewal additionally requires CRON_ENABLED=true; the meeting pipeline
requires PIPELINE_ENABLED (on by default) and writes into CODING_WORKSPACE_DIR.