Cameleer

Slack component

The slack component posts messages to Slack channels (incoming webhook or the chat.postMessage Web API) and reads new channel messages by polling conversations.history.

Scheme: slack: · Crate: cameleer-saas · Cargo feature: saas · Consumer: yes · Producer: yes · Apache Camel: Slack

When to use it

  • Post alerts, deployment notices or daily reports to a channel.
  • Let an AI agent publish its summaries or answers to a team channel.
  • React to messages people write in a channel (a support bot, a "deploy" keyword, a triage queue).
  • Mirror a channel into another system (a ticket tracker, a database, a search index).

URI format

text
slack:#channel[?options]
slack://channel[?options]

The channel is a name (#ops, general) or a channel id (C0123456). The producer needs either webhookUrl or token; the consumer always needs token.

Example

Post a message with an incoming webhook. A text body becomes the message text; username and iconEmoji are added to the webhook payload.

yaml example: slack-webhook-post
- route:
    id: deploy-notice
    from:
      uri: "timer:deploy-notice?repeatCount=1"
      steps:
        - setBody:
            constant: "Deployment of checkout v42 finished"
        - to: "slack:#ops?webhookUrl={{env:SLACK_WEBHOOK_URL}}&username=cameleer&iconEmoji=:rocket:"

An AI agent that summarises an incident report with an LLM and posts the summary through the Web API (chat.postMessage with a bot token). The Web API response is kept in the CamelSlackResponse header.

yaml example: slack-agent-summary
- route:
    id: incident-summary-to-slack
    from:
      uri: "direct:incident-report"
      steps:
        - to: "openai:chat-completion?model={{env:OPENAI_MODEL:gpt-4o-mini}}&baseUrl={{env:OPENAI_BASE_URL:https://api.openai.com/v1}}&apiKey={{env:OPENAI_API_KEY}}&temperature=0&systemMessage=Summarise this incident report in two sentences for the on-call channel."
        - setBody:
            simple: ":memo: ${body}"
        - to: "slack:#general?token={{env:SLACK_TOKEN}}&serverUrl={{env:SLACK_API_URL:https://slack.com}}"
        - log: "posted to Slack at ts ${header.CamelSlackResponse[ts]}"

Read new messages from #general. Each message becomes one exchange whose body is the Slack message object (text, user, ts, ...). The first poll delivers the latest maxResults messages; later polls deliver only newer ones.

yaml example: slack-read-channel
- route:
    id: read-general
    from:
      uri: "slack://general?token={{env:SLACK_TOKEN}}&serverUrl={{env:SLACK_API_URL:https://slack.com}}&maxResults=20&naturalOrder=true&delay=5000"
      steps:
        - filter:
            simple: "${body[text]} contains 'deploy'"
            steps:
              - setBody:
                  simple: "${body[user]} asked: ${body[text]}"
              - to: "log:slack-deploy-requests"

Rust DSL

rust
ctx.add_routes(|b| {
    b.from("timer:deploy-notice?repeatCount=1")
        .set_body(constant("Deployment of checkout v42 finished"))
        .to("slack:#ops?webhookUrl={{env:SLACK_WEBHOOK_URL}}&username=cameleer&iconEmoji=:rocket:");
})?;

Options

optiondefaultdescription
webhookUrlIncoming webhook URL. When set, the producer posts to the webhook.
tokenBot or user token (xoxb-...). Producer: chat.postMessage. Required by the consumer.
usernameDisplay name added to webhook payloads.
iconUrlIcon URL added to webhook payloads (icon_url).
iconEmojiIcon emoji added to webhook payloads (icon_emoji), e.g. :rocket:.
maxResults10Consumer: messages fetched per poll (limit).
naturalOrderfalseConsumer: deliver the oldest message first (Slack returns newest first).
conversationTypePUBLIC_CHANNELConsumer: channel type used to resolve the name: PUBLIC_CHANNEL, PRIVATE_CHANNEL, MPIM, IM.
serverUrlhttps://slack.comWeb API base URL (Cameleer extension: a proxy, a gateway or a test server).
delay, initialDelay, ...delay=10000Consumer: the standard scheduled-poll options.

Message headers

headerdirectiondescription
CamelSlackResponseout (producer)The Web API response of chat.postMessage (ok, channel, ts). Not set for webhooks.

The message body decides the payload: a text body is the message text; a map body is sent as the whole payload (blocks, attachments, thread_ts, ...; channel is added when missing).

Run it with Docker

sh
export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T000/B000/XXXX
docker run --rm -e SLACK_WEBHOOK_URL -v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/deploy-notice.camel.yaml

Common questions

Webhook or token: which one should I use?

A webhook is the simplest: one URL, one channel, no scopes. Use a bot token (chat:write scope, plus channels:history and channels:read for the consumer) when you need to post to several channels, read messages, or get the message ts back for threads.

How do I send blocks or reply in a thread?

Make the body a map, for example with unmarshal: json on a JSON string such as {"text":"fallback","thread_ts":"1700000001.000100","blocks":[...]}. Map bodies are sent as the payload unchanged.

What happens when Slack rejects the message?

With a token, a response with "ok": false fails the exchange with an ApiException whose message is the Slack error (Slack: channel_not_found). With a webhook, a non-2xx response fails with HttpOperationFailedException. Use onException or errorHandler to retry.

Is Slack's Socket Mode or Events API supported?

No. The consumer polls conversations.history. For push delivery, expose an HTTP endpoint with platform-http and point a Slack event subscription at it.

Found a problem?

If something on this page doesn't match what Cameleer does, or you hit a bug while building with it, please help fix it, whether you are a person or a coding agent: open an issue that describes what you saw, then fork the repository, fix it, add or update a test, run cargo test --workspace, and open a pull request. CONTRIBUTING.md explains the ground rules.

Edit this page on GitHub