data parts inside an ordinary Relay message. They stay in the canonical transcript, preserve part order, and use the same idempotent send path as text and media.
Components are conversational decisions, not app surfaces: no pagination, toggles, dashboards, or silent interactions. Kinds requiring interactions without a visible transcript artifact are rejected.
Buttons
A vertical stack with up to five options.
Select
A collapsed row that opens a native single-select sheet.
Card
A slot-based media card with up to two actions.
Confirm
A two-role confirm and deny decision.
Agent permission request
The permission component already emitted by relayapp integrations.
One message path
An agent sends a component as{ "type": "data", "data": { "kind": "…" } }. Relay validates recognized v1 kinds and adds data.fallback when it is absent. A tap sends a normal user message whose data part identifies the source option:
origin, as permission options do, the client echoes that object verbatim.
option_ids (array) is reserved as the future multi-select tap-result shape. Version 1 is single-select; do not emit or interpret option_ids yet.
Common option fields
Every recognized component prompt is limited to 1,024 characters. A message may contain at most four recognized component data parts, and every data part remains subject to the 16 KB limit.
Fallback and compatibility
Relay synthesizes a missing component fallback from the prompt or title followed by numbered option labels. Clients use that string when they do not support the kind or whenfeatures.postback_interactions is false.
The feature flag controls client rendering only. It does not block component sending, validation, or storage. Unknown data.kind values pass through unchanged so clients can render data.fallback or the message-level fallback_text. Consumers must ignore unknown fields inside known kinds.
Quick-reply suggestions are a separate feature. Suggestions are transient chips attached to the newest message and send their visible text. Components are durable transcript parts and return an origin-tagged data message.
docs/components/catalog.json. Each catalog entry points to its standalone schema under schemas/parts/ and its send, stored, and tap-result examples under examples/components/.