Skip to main content

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_ID for a public-client device-code sign-in; you add a delegated OnlineMeetingTranscript.Read.All + OnlineMeetings.Read consent 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:

  1. Graph credentials -- set GRAPH_TENANT_ID / GRAPH_CLIENT_ID / GRAPH_CLIENT_SECRET, then check Token health.
  2. Webhook listener -- set MSGRAPH_WEBHOOK_CLIENT_STATE, MSGRAPH_WEBHOOK_NOTIFICATION_URL (a public, tunnel-reachable URL), and MSGRAPH_WEBHOOK_RESOURCE, then run Validate.
  3. Teams pipeline -- run a manual Fetch for a known meeting to confirm the summary pipeline end-to-end.
  4. 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

VariableDefaultDescription
WEBHOOK_ENABLEDfalseMaster switch for the whole feature.
WEBHOOK_INGRESS_BASE_PATH/api/webhookBase path; sources mount at <base>/{source}.
WEBHOOK_STORE_DIR.webhooksPer-source state, receipts, and subscriptions.
WEBHOOK_RECEIPT_MAX_BYTES1048576Cap 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_HOURS12Renewal 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_URLhttps://graph.microsoft.com/v1.0Optional Graph base URL override.
TEAMS_MEETING_OUTPUT_DIRmeeting-summariesOutput 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.