LandfallDocs
Integrations · Chat

Connecting Slack to Landfall

Slack is a channel Landfall posts incident updates to, and optionally a place to vote on an open decision. Landfall never reads your workspace's message history.

  • As a channel: an update a person approves in Landfall posts into a Slack channel. Takes a Slack app's Bot User OAuth token.
  • As a decision channel (optional): people in a bridged channel vote on an open decision from Slack. Takes the same app's Signing secret as well.
Landfall
approved update
→
Slack
#incidents
→
Landfall
a vote click, if you enable it

What you'll need

  • Permission to create a Slack app in your workspace, or an existing app you can change.
  • An admin on your Landfall organization, to save the connection under Integrations.
  • A personal Landfall API key for the admin, to turn on real egress (it has no screen yet).
  • Only for the decision bridge: your Slack workspace ID, and the right to set an Interactivity Request URL on the app.

1. Create a Slack app in Slack

  1. api.slack.com/apps → Create New App

    Create the app in the workspace that should receive incident updates.

  2. OAuth & Permissions → Bot Token Scopes

    Add chat:write, users:read, users:read.email and channels:manage. Landfall uses them to post and update messages, to create a channel for one incident, to match a responder by email, and, for the decision bridge, to resolve the person who clicked a vote button.

  3. OAuth & Permissions → install the app to your workspace

    Approve the install, then copy the Bot User OAuth token. It starts with xoxb-. Invite the app to each channel it should post in, for example #incidents.

2. Add it to Landfall

  1. Integrations → Chat → Slack

    Open Integrations in the left menu and select the Slack tile under Chat. Paste the token into Bot User OAuth token (xoxb-…). Default channel is optional and is saved with the connection; the incident's Comms tab posts to #incidents today, whatever this field says. Leave Signing secret empty unless you set up voting in step 3.

    app.landfalls.ai · Integrations · Slack
    The Slack panel in Landfall, Not configured, with the Bot User OAuth token masked, Default channel set to #incidents, the Signing secret masked, the chat scope, and the Test connection and Save integration buttons.
    The Slack panel before saving, with #incidents as the default channel. The Signing secret is filled in here too; you need it only for votes from Slack. The token and the secret in this picture are masked.
  2. Test connection

    Landfall calls Slack's auth.test with the token. Nothing is posted. A working token shows ✓ connected and the line connected to Slack team <your team>.

  3. Save integration

    The token and the signing secret go to Landfall's secrets backend and are never shown again. The panel and the Slack tile read Configured.

  4. Turn on real egress (API only)

    Real egress is off for every organization by default. Until it is on, an approved update is recorded in the room and not delivered, and the Comms tab says so. The switch has no screen yet. An admin turns it on with a personal API key from Your settings → API keys:

    Terminal
    curl -X PUT https://api.landfalls.ai/o/<your-org>/oncall/egress \
      -H "Authorization: Bearer lf_key_…" \
      -H "Content-Type: application/json" \
      -d '{"enabled": true}'

    The switch covers every chat connection in the organization: Slack, Microsoft Teams, Telegram and Buzz. The change is audited.

3. Optional: let people vote from Slack

Existing connections keep working, unchanged. The decision bridge is off until you complete this section. Until then Landfall refuses every inbound delivery from Slack: no signing secret is stored, and a connection without one cannot accept a click.

  1. Basic Information → App Credentials → Signing Secret

    Copy the app's Signing Secret. It proves an inbound click came from your workspace. Landfall checks it on every delivery and refuses anything that does not match, including a replay of a real click more than five minutes old.

  2. Interactivity & Shortcuts → Interactivity → Request URL

    Turn Interactivity on and set the Request URL to https://api.landfalls.ai/triggers/slack/<your-org-slug>. The org slug is the slug= value in your Landfall address bar. Slack posts to this URL each time someone clicks a Landfall button.

  3. Integrations → Chat → Slack → Signing secret

    Paste the secret into Signing secret and click Save integration. Like the token, it is stored in the secrets backend and no API returns it.

  4. Bridge one incident's channel, and approve it (API only)

    The bridge is set per incident, by an admin, through the API. Bind it with your Slack workspace ID (a T… value) and choose whether votes may be cast from the channel. With the channel open in Slack in a browser, the address reads app.slack.com/client/<workspace ID>/<channel ID>. channelRef is optional when the incident already has a channel; it defaults to that one. Then grant the bridge's standing approval:

    Terminal
    curl -X POST https://api.landfalls.ai/o/<your-org>/incidents/<incident-id>/oncall/chat-bridge \
      -H "Authorization: Bearer lf_key_…" \
      -H "Content-Type: application/json" \
      -d '{"workspaceRef": "T0123456789", "channelRef": "C0123456789", "inboundVotesEnabled": true}'
    
    curl -X POST https://api.landfalls.ai/o/<your-org>/incidents/<incident-id>/oncall/chat-bridge/approval \
      -H "Authorization: Bearer lf_key_…"

    The approval lets an entry post without someone approving each message. It is bound to the exact configuration you approved: change the channel, or turn voting on or off, and it stops applying at once and entries go back to waiting for a person. DELETE on the same /approval path revokes it.

What it looks like

An update a person approves on an incident's Comms tab posts in #incidents, and the tab confirms it with Approved and sent to #incidents for <room>. Through the API, Landfall can also create a channel for one incident, named inc-<incident id> (POST /o/<org>/incidents/<incident-id>/oncall/channel/ensure), and draft a page to a PagerDuty responder whose email matches a Slack account (POST /o/<org>/incidents/<incident-id>/oncall/page). A page waits for a person's approval like any other update.

A bridged channel gets one post per significant entry, each naming who or what produced it: a new finding, a new hypothesis, a decision opened or reached, a line of investigation ruled out, and the incident resolved or closed. The room's conversation and anyone's local investigation capture are never relayed. Each vote clicked in Slack, accepted or refused, is recorded on the incident's timeline.

If Slack is unavailable, the incident is unaffected; nothing in Landfall waits on the bridge in either direction. A vote clicked in Slack during a Slack outage is never delivered, and Landfall cannot learn it happened. The war room stays the authoritative place to vote, and an open decision stays open until it is decided there.

What Beacon can read

Not applicable. Slack is not in the signal catalog, so Beacon and joined agents cannot query it. Landfall reads no message history; the only reads are auth.test, an email lookup for an on-call responder, and, with the decision bridge on, one profile lookup for the person who clicked. See Integrations architecture for the sources that are in the catalog.

Opening incidents from Slack

Not applicable. The /triggers/slack/<org-slug> route takes vote clicks from the decision bridge and never opens an incident. A chat message can open a room from Buzz instead, and alerts open rooms through the Triggering integrations pages, such as Alertmanager.

Troubleshooting

Test connection failed?
  • Slack: invalid_auth or Slack: not_authed: the token is wrong or was revoked. Copy the Bot User OAuth token again from OAuth & Permissions.
  • botToken required: the token field is empty.
Connected, but nothing reaches the channel?
  • The Comms tab says No channel connected, so this is recorded in the room and not delivered. Real egress is off; turn it on (step 2).
  • The tab says Not delivered: Slack chat.postMessage: not_in_channel. Invite the app to the channel in Slack, then send again.
  • Two Slack connections in one organization: Landfall will not guess between them and sends through neither. Keep one.
A vote from Slack did nothing?
  • No signing secret is saved, so every click is refused. Finish step 3.
  • The person's Slack profile has no email Landfall knows. The vote is refused and recorded on the timeline; Slack shows them nothing.

Reference

FieldValue
Bot User OAuth token (xoxb-…)Required. The app's bot token.
Default channelOptional, for example #incidents. Saved with the connection; the Comms tab posts to #incidents today.
Signing secretOptional. Needed only to accept votes cast from Slack; from Basic Information → App Credentials.
Bot token scopeschat:write, users:read, users:read.email, channels:manage
Read operationsauth.test, users.lookupByEmail, users.info. No message history.
AccessWrites chat.postMessage and chat.update, each only after a person's approval or a standing approval, and conversations.create when someone creates a channel for an incident.
Real egressOff by default. PUT /o/<org>/oncall/egress with {"enabled": true}; admin only, audited.
Interactivity Request URLhttps://api.landfalls.ai/triggers/slack/<org-slug>
Where the secrets are storedLandfall's secrets backend. Never shown again and never returned by an API.
RevokeUninstall the app from your workspace in Slack. To remove the connection from Landfall, an admin calls DELETE /o/<org>/integrations/slack/connections/default; its secrets go with it.
Trigger endpointNone. Slack cannot open an incident.

See Integrations architecture for how every Landfall integration shares this connector shape, and how the inbound decision path is verified.