Google Chat Roadmap
Developer notes for the Google Chat upstream connector: how Triage’s diagnostic runs as a Chat app, rendered with Cards v2 over the Chat API. The gateway’s Google Chat renderer already ships in the reference implementation; the hosted transport is on the roadmap. Facts here are grounded in Google’s machine-readable Chat API discovery document.
The public platform facts the Intake Gateway’s Google Chat renderer relies on. Method names, scopes and field names are taken from the Chat API v1 discovery document (revision 2026-08-15) and the pages listed under Developer references.
| App & install | A Chat app configured in a Google Cloud project (Chat API configuration) and published to a Workspace organisation or the Marketplace. Base URL https://chat.googleapis.com, REST v1. |
|---|---|
| Authentication | App authentication with a service account for the app’s own actions (scope chat.bot, or the granular chat.messages.create / chat.messages); user authentication with OAuth when acting for a person. Inbound deliveries carry a bearer JWT signed by chat@system.gserviceaccount.com with the audience set to the app’s project number, verified against Google’s published keys. |
| Post a question | spaces.messages.create: POST /v1/{parent=spaces/*}/messages with a cardsV2 payload. Optional requestId makes the create idempotent: an existing request ID returns the message it already created instead of posting a second one. privateMessageViewer keeps a question visible to one named person, so a diagnostic can run inside a busy space. |
| Lock in place | spaces.messages.patch (PATCH /v1/{name=spaces/*/messages/*}) with updateMask=cardsV2 replaces the card in place, leaving an answered question with no buttons. A custom messageId at create time means the app can update or delete later without storing Chat’s own resource name. |
| Question rendering | Cards v2: a message carries a list of {cardId, card} pairs, each card at most 32 KB, built from textParagraph, decoratedText, buttonList, divider, plus textInput, selectionInput and dateTimePicker. Where one step needs several fields at once the app answers actionResponse.type = DIALOG with a dialogAction.dialog.body card instead. |
| Interactivity | A button’s onClick.action names a function and parameters; Chat posts a CARD_CLICKED event back and the app reads commonEventObject.invokedFunction, .parameters and .formInputs.WIDGET_NAME. Typed events cover MESSAGE, ADDED_TO_SPACE, REMOVED_FROM_SPACE, CARD_CLICKED, WIDGET_UPDATED, APP_COMMAND, APP_HOME and SUBMIT_FORM. |
| Transport | An HTTPS endpoint, a Pub/Sub topic, or Apps Script. A synchronous reply must be posted within 30 seconds; anything slower answers asynchronously by calling the Chat API. spaces.spaceEvents.list replays typed history such as google.workspace.chat.message.v1.created, so a missed delivery is recovered by reading rather than by hoping. Quotas are per space and per project: 60 writes per minute per space, and an exceeded quota returns 429 to retry with backoff. |
| Identity | The acting person arrives as user on the event (name, displayName, email where the scope allows), which is what the gateway records as the requester. |
| Step | What happens on the platform |
|---|---|
| 1 | The requester opens the Triage app in Google Chat, or @mentions it in a space. Chat delivers a MESSAGE or APP_COMMAND interaction event to the gateway endpoint, carrying a bearer JWT. |
| 2 | The gateway verifies the JWT against Google’s published keys, checks issuer and audience, rejects anything unverifiable with 401, then resolves the requester from user and the conversation from space and thread. |
| 3 | The gateway posts the first question with spaces.messages.create: one Cards v2 card, one question, buttons carrying the answer values. In a shared space the message sets privateMessageViewer so only the requester sees it. |
| 4 | A click delivers a CARD_CLICKED event within the 30 second window; the gateway reads commonEventObject.invokedFunction and .parameters, records the answer, and calls spaces.messages.patch with updateMask=cardsV2 to replace the card with a locked version that has no buttons. Where a step needs several fields it answers DIALOG instead and reads formInputs on submit. |
| 5 | On the final answer the gateway calls the Triage decision core; the Intent Record is minted and the completion card (channel, confidence, intent:// chip) is sent. |
| 6 | When composerID publishes downstream, the gateway updates the completion card with a button that deep-links to the created record. |
Google’s official developer documentation. The REST facts on this page come from the machine-readable discovery document, which is the same artefact Google’s own client libraries are generated from.
The gateway’s Google Chat renderer and its contract tests live in upstream/google_chat_cards.py in this repository: the same gateway core, a different renderer. Locking is structural on this surface too: the answered card is replaced via updateMask=cardsV2 with a version that has no buttons.