Skip to main content
A template keeps its ID for its whole life. Its content lives in versions: numbered snapshots of its blocks and sample data. Exactly one version is live at a time. That is the version every send, compile, schedule, digest and slash command uses, whichever integration makes the call. The status field on templates and versions is a free-text label kept for compatibility. Nothing enforces it. A version labelled draft can be live, and one labelled published might not be. Use is_current and lifecycle to know what will send.
status is deprecated as of September 26, 2026. It is still accepted and returned unchanged, but stop sending it: a request that includes it gets a Deprecation response header and a Link to this page. Its removal will be announced in the changelog in advance.

In the builder

Saving in the builder creates a new version and makes it live immediately. Every integration sends the new content from that moment. If a template is in active use, try changes on a duplicate first, or use the API workflow below.

Over the API

Changing content and making it live are separate steps with separate scopes. A key with templates:update can prepare versions, while only a key with templates:activate can put one live.
  1. Create a version: POST /v1/templates/{id}/versions with blocks, plus an optional sample_data and a note saying why. The blocks must compile or nothing is created. The new version is never live on creation, so sends keep using the live version.
  2. Check it: POST /v1/templates/validate is a free dry run of the same blocks.
  3. Activate it: POST /v1/templates/{id}/versions/{version_id}/activate. The version is validated again first: its blocks must still compile, and its buttons may only reference destinations and modals that still exist in your organization.
Pass expected_current_version_id with the live version you read before deciding. If someone else activated a different version in the meantime, the request fails with 409 current_version_changed. The response includes current_version_id, so you can look again rather than overwrite their change. Without it, activation behaves as it always has. Activating the version that is already live changes nothing (changed: false). Template creation, version creation and activation all accept an Idempotency-Key, so a retry after a network failure replays the first answer instead of acting twice. Compile and send responses include version_id and version_number: the version that was actually used.

Roll back

Rolling back is activating an earlier version. GET /v1/templates/{id}/activations lists every change of the live version, newest first:
  • which version went live, and which one it replaced;
  • who made the change;
  • where it came from: web, api, mcp or system. Builder saves and restores are recorded as legacy, and migration marks the version that was live when the history began;
  • the note, if one was given.
A rollback changes what future sends use. It does not edit or retract messages already in Slack, and it cannot undo what their buttons already did.

Schedules and digests

Scheduled messages and batch digests created through the API send the version that was live when they were created. Later activations do not change them, including recurring messages. Batch digests created in the web app use the live version at the time each digest is sent.

Archive a template

Archiving retires a template without losing anything. An archived template cannot be sent, compiled, versioned or activated (409 template_archived), but its versions, live version and history are all kept. POST /v1/templates/{id}/unarchive returns it to service exactly as it was.
Archiving is refused with 409 template_in_use while anything would still send the template on its own: scheduled messages that are waiting, active digests, or /lb-send. The response’s uses counts each, so you know what to pause or move first. LithoBlocks does not pause them for you. Prefer archiving to deleting. Deleting a template also deletes its send history. Template lifecycle · API authoring