action_config,
and the API checks it before anything is stored.
What a button can carry
Buttons can sit in an
actions block, as a section accessory, in context_actions, on a card,
or on a carousel card. Where a button sits decides which update strategies make sense:
Payload variables
Dynamic carousel actions automatically retain the selected item. Use
{{rowData.id}}
in webhook payloads and rowData.id in modal data bindings; context.* continues
to refer to the complete message data. This context survives modal submission and
replace_card updates. Submitted inputs are under submission.values.*, while
resolved modal bindings are under modal.*. this and item are selected-item
aliases. Put business IDs in button values or payload fields: generated carousel
action IDs include a suffix used for routing. Re-send older messages to use this
behavior.
GET /v1/templates/block-schema returns this whole contract as data under interactivity, so an
assistant can read it rather than remember it.
What the API checks
POST /v1/templates/validate, POST /v1/templates and POST /v1/templates/{id}/versions all
check every configured button and refuse, or report, when:
- the
action_confighas the wrong shape (an unknown strategy,replace_blockwithouttarget_block_id, aroutewithout a destination, a message update without idempotency); - a
destination_idis not an active destination in your organization, or amodal_definition_idis not one of your active modals; - a strategy is not available for the button’s position;
- the complete message metadata cannot fit 4,000 bytes, including wrapper and log references,
even after lossless gzip/base64 compression, or exceeds the 65,536-byte decoded safety limit.
Action configs travel inside each sent message with its original data, preserving the behavior
configured when sent. Existing uncompressed messages remain supported.
validatereports rawinteractivity.metadata_bytesand addsmetadata_transportwith the selected encoding,wire_bytes, andbudgeted_bytesincluding reserved logging IDs.
Gzip/base64 compression and
metadata_transport diagnostics are an unreleased prototype. Production retains the 3,800-byte event-payload budget until live Slack acceptance and deployment.valid: false and one error per problem naming the action_id; create and
version answer 400 with code: "invalid_data" and the same list under issues. Nothing is stored
until every check passes. Use validation errors to fix the configured action before sending.
Complete the workflow
- Create a destination and keep its returned ID.
- If collecting input, create and activate a modal.
- Add the button to a template, validate, save a version, and activate it.
- Send to a test channel and trigger the action.
- Inspect interaction history and the receiver’s records.
Idempotency-Key. Reuse the key and identical body only for retries of the same intended operation. In-progress or uncertain outcomes need reconciliation; do not rotate the key to force execution.
Action configuration and send data travel with the posted message. Editing a template does not retrofit old Slack messages. Deleted or inactive destinations and modals can make their old buttons fail.
MCP clients expose these operations using the same permissions. Read and validate before requesting a write, and preserve idempotency keys for retries.
Supported replacement blocks
Every update strategy accepts concrete blocks with value placeholders. Concrete cards, static carousels (elements), tables, and other concrete message blocks use the shared
message compiler. Both clicks and modal submissions use the same replacement logic as the
editor preview. Button action_config templates remain deferred until that button’s next
click; metadata is generated from the final compiled message before Slack-only sanitization.
Dynamic arrayPath blocks, cardTemplate, tasksArrayPath/taskTemplate, directive
containers, inline conditional/loop directives, and index arithmetic are unsupported in all update
strategies. The editor and API report unsupported_update_construct; runtime rejects
these configurations before contacting Slack. Supply concrete replacement blocks, or send
a new message using the normal template compiler. Initial sends still support dynamic
carousels and directives. {{@index}} is a direct value binding; compute derived indices in your data.
Missing and ambiguous targets fail with
missing_update_target or
ambiguous_update_target. They do not silently append replacements. The preview requires
a selected click target for strategies that depend on it.
Older messages and selected-item diagnostics
Deploying handlers or editing a template does not change metadata already attached to a Slack message. Compatibility depends on what the original message retained:
An action-ID suffix alone cannot identify an item. Never parse business data from generated
action IDs. Put it in a button
value or an explicit payload field instead. No deployment
can reconstruct item data that an old message never carried.
A requested rowData, item, this, or @index binding with no corresponding context
fails with missing_item_context. A field absent from an available item reports
missing_binding. The same checks apply to webhook payloads/headers, modal data bindings,
and replacement blocks. They preserve explicit null, false, and zero values. Required
modal bindings and all replacement-block bindings must resolve. Optional legacy root
bindings in webhook payloads and modal mappings retain their existing unresolved-placeholder
behavior; this compatibility exception does not apply to selected-item bindings.
The editor shows these diagnostics in mapping/update previews. Runtime update failures are
attached to the original interaction in message update history; modal and webhook mapping
failures appear in interaction history. An unresolvable action configuration is reported
to the person clicking the button.
Re-send procedure
- Open the affected template and inspect the old message’s interaction history. Determine whether the action or selected-item reference is missing; do not choose a row by its position or a duplicated business ID.
- Correct and activate the template version. Use explicit business values/payload fields and concrete update blocks. Validate it with representative send data.
- Use the normal send workflow with complete current data and the intended workspace/channel. This is a deliberate new send. Use a new idempotency key for this new operation and reuse it only for retries of that operation.
- Check the second card’s webhook/modal mapping, its concrete replacement, and the next click. Inspect interaction history for the new message.
- Direct users to the new message and retire the old message through your normal channel process. Already-open modals and old message links retain their old context.

