Skip to main content
Check environment and feature availability before following this guide.
Some messages should not outlive their moment: a one-time code, an offer that closes, an incident that resolves, an approval that has been decided. An expiring message is replaced with a notice that it expired, or deleted. Its buttons stop working the moment the deadline passes. Expiry is free. It runs about once a minute, so a lifetime is at least 60 seconds.

When it expires, what happens

Expire a message when you send it

Add expiration to /v1/templates/send or /v1/templates/send-bulk:
The response adds expires_at. Expiring at send time needs only messages:create. Scheduled messages take the same expiration. after_seconds counts from each delivery, so it suits recurring messages. at must come after send_at and can’t be combined with recurrence; an occurrence that would post after its at isn’t sent at all. See Schedule a message.

Expire every message from a template

A template version can carry an expiry policy, which applies to every send of it: the API, the web app, /lb-send, scheduled messages and batch digests. In the builder, open the gear next to the template’s name and choose Expiry. Over the API, pass expiration when you create the template or a version:
  • default applies to a send that names no expiry.
  • max_after_seconds is the longest a message may live. A send asking for longer is refused with 422 expiration_exceeds_maximum before anything is posted or charged. With no default, the maximum becomes the default, so no message from this template outlives it.
  • notice replaces the system notice. It’s filled in with the send’s data when the message is sent, and its placeholders count in the template’s request format. It can’t hold anything a reader could click or fill in.
The policy is part of the version, like the blocks: it goes live when the version does.

Expire a message later

In the web app, open the message in Sent messages and choose Expire.

Expire it now, when something happens

This is the hook for “expire when the incident resolves”: the automation that knows calls it.
Expiring by reference acts on at most 100 messages per call. A member’s call leaves alone the messages others sent and says how many in not_permitted. If Slack refuses an expire-now for the moment, the expiry stays due and is retried within minutes. Its buttons already don’t work. These need messages:update, with the same rules for who may change which message as correcting. Over MCP they’re set_message_expiration, cancel_message_expiration, expire_message and expire_messages_by_reference.

What expiry can’t do

Expiry removes the message from Slack and, by default, LithoBlocks’ copy. It can’t take back what has already been seen:
  • people who read it, and push or email notifications already delivered;
  • AI tools that already read the channel;
  • your workspace’s retention settings, exports and legal holds;
  • thread replies that quoted it.
Don’t put secrets in a message’s notification text: it’s what notifications show. Expiry is the right tool when a message must stop being current. It doesn’t make something that was once shown confidential.