{"openapi":"3.1.0","info":{"title":"Ferrule Slack API","version":"1.0.0","description":"REST API for Slack via the Ferrule gateway.","contact":{"name":"Ferrule","url":"https://ferrule.io"}},"servers":[{"url":"https://0.0.0.0:3000","description":"Ferrule gateway"}],"paths":{"/api/v1/slack/channels/{channel}/messages":{"post":{"operationId":"slack.send_message","description":"Send a message to a Slack channel. Can also reply to a thread by providing thread_ts.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID to send the message to"},"required":true,"description":"Channel ID to send the message to"},{"in":"query","name":"text","schema":{"type":"string","description":"Message text to send"}},{"in":"query","name":"thread_ts","schema":{"description":"Thread timestamp to reply to (creates a threaded reply)","type":"string"}},{"in":"query","name":"reply_broadcast","schema":{"description":"When replying in a thread, also post to the channel (default false)","type":"boolean"}},{"in":"query","name":"unfurl_links","schema":{"description":"Enable or disable link unfurling (default true)","type":"boolean"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Request body parameters"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"channel":{"type":"string"},"ts":{"type":"string"},"message":{"type":"object","properties":{"type":{"type":"string"},"subtype":{"type":"string"},"text":{"type":"string"},"ts":{"type":"string"},"user":{"type":"string"},"bot_id":{"type":"string"},"thread_ts":{"type":"string"},"reply_count":{"type":"number"},"reply_users_count":{"type":"number"},"latest_reply":{"type":"string"},"reactions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"number"},"users":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}},"get":{"operationId":"slack.read_messages","description":"Read message history from a Slack channel. Use oldest/latest to filter by time range.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID to read messages from"},"required":true,"description":"Channel ID to read messages from"},{"in":"query","name":"limit","schema":{"description":"Maximum number of messages to return per page (default 20, max 999)","type":"string"},"description":"Maximum number of messages to return per page (default 20, max 999)"},{"in":"query","name":"cursor","schema":{"description":"Pagination cursor from previous response's response_metadata.next_cursor","type":"string"},"description":"Pagination cursor from previous response's response_metadata.next_cursor"},{"in":"query","name":"oldest","schema":{"description":"Only messages after this Unix timestamp (inclusive). Example: 1234567890.123456","type":"string"},"description":"Only messages after this Unix timestamp (inclusive). Example: 1234567890.123456"},{"in":"query","name":"latest","schema":{"description":"Only messages before this Unix timestamp (inclusive). Example: 1234567890.123456","type":"string"},"description":"Only messages before this Unix timestamp (inclusive). Example: 1234567890.123456"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"messages":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"subtype":{"type":"string"},"text":{"type":"string"},"ts":{"type":"string"},"user":{"type":"string"},"bot_id":{"type":"string"},"thread_ts":{"type":"string"},"reply_count":{"type":"number"},"reply_users_count":{"type":"number"},"latest_reply":{"type":"string"},"reactions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"number"},"users":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}}},"additionalProperties":{}}},"has_more":{"type":"boolean"},"response_metadata":{"type":"object","properties":{"next_cursor":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels/{channel}/messages/{ts}/replies":{"get":{"operationId":"slack.read_thread","description":"Read replies in a message thread. Provide the channel and the parent message timestamp.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID containing the thread"},"required":true,"description":"Channel ID containing the thread"},{"in":"path","name":"ts","schema":{"type":"string","description":"Parent message timestamp (thread root)"},"required":true,"description":"Parent message timestamp (thread root)"},{"in":"query","name":"limit","schema":{"description":"Maximum number of replies to return per page (default 20, max 999)","type":"string"},"description":"Maximum number of replies to return per page (default 20, max 999)"},{"in":"query","name":"cursor","schema":{"description":"Pagination cursor from previous response's response_metadata.next_cursor","type":"string"},"description":"Pagination cursor from previous response's response_metadata.next_cursor"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"messages":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"subtype":{"type":"string"},"text":{"type":"string"},"ts":{"type":"string"},"user":{"type":"string"},"bot_id":{"type":"string"},"thread_ts":{"type":"string"},"reply_count":{"type":"number"},"reply_users_count":{"type":"number"},"latest_reply":{"type":"string"},"reactions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"number"},"users":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}}},"additionalProperties":{}}},"has_more":{"type":"boolean"},"response_metadata":{"type":"object","properties":{"next_cursor":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels":{"get":{"operationId":"slack.list_channels","description":"List Slack channels the bot has access to. Returns public channels by default.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"query","name":"limit","schema":{"description":"Maximum number of items to return per page (default 20, max 999)","type":"string"},"description":"Maximum number of items to return per page (default 20, max 999)"},{"in":"query","name":"cursor","schema":{"description":"Pagination cursor from previous response's response_metadata.next_cursor","type":"string"},"description":"Pagination cursor from previous response's response_metadata.next_cursor"},{"in":"query","name":"types","schema":{"description":"Comma-separated channel types: public_channel, private_channel, mpim, im (default: public_channel)","type":"string"},"description":"Comma-separated channel types: public_channel, private_channel, mpim, im (default: public_channel)"},{"in":"query","name":"exclude_archived","schema":{"description":"Set to true to exclude archived channels (default false)","type":"string"},"description":"Set to true to exclude archived channels (default false)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"channels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"is_channel":{"type":"boolean"},"is_group":{"type":"boolean"},"is_im":{"type":"boolean"},"is_mpim":{"type":"boolean"},"is_private":{"type":"boolean"},"is_archived":{"type":"boolean"},"is_member":{"type":"boolean"},"created":{"type":"number"},"creator":{"type":"string"},"name_normalized":{"type":"string"},"num_members":{"type":"number"},"topic":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}},"purpose":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}}},"additionalProperties":{}}},"response_metadata":{"type":"object","properties":{"next_cursor":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}},"post":{"operationId":"slack.create_channel","description":"Create a new Slack channel. Provide a name (lowercase, no spaces).","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"query","name":"name","schema":{"type":"string","description":"Channel name (lowercase, no spaces, max 80 chars)"}},{"in":"query","name":"is_private","schema":{"description":"Create as private channel (default false)","type":"boolean"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Request body parameters"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"channel":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"is_channel":{"type":"boolean"},"is_group":{"type":"boolean"},"is_im":{"type":"boolean"},"is_mpim":{"type":"boolean"},"is_private":{"type":"boolean"},"is_archived":{"type":"boolean"},"is_member":{"type":"boolean"},"created":{"type":"number"},"creator":{"type":"string"},"name_normalized":{"type":"string"},"num_members":{"type":"number"},"topic":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}},"purpose":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels/{channel}":{"get":{"operationId":"slack.get_channel_info","description":"Get detailed information about a Slack channel including topic, purpose, and member count.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID"},"required":true,"description":"Channel ID"},{"in":"query","name":"include_num_members","schema":{"description":"Include the number of members in the channel","type":"boolean"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"channel":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"is_channel":{"type":"boolean"},"is_group":{"type":"boolean"},"is_im":{"type":"boolean"},"is_mpim":{"type":"boolean"},"is_private":{"type":"boolean"},"is_archived":{"type":"boolean"},"is_member":{"type":"boolean"},"created":{"type":"number"},"creator":{"type":"string"},"name_normalized":{"type":"string"},"num_members":{"type":"number"},"topic":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}},"purpose":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels/{channel}/archive":{"post":{"operationId":"slack.archive_channel","description":"Archive a Slack channel. The channel can be unarchived later.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID to archive"},"required":true,"description":"Channel ID to archive"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Request body parameters"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels/{channel}/invitations":{"post":{"operationId":"slack.invite_to_channel","description":"Invite one or more users to a Slack channel. Provide comma-separated user IDs.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID to invite users to"},"required":true,"description":"Channel ID to invite users to"},{"in":"query","name":"users","schema":{"type":"string","description":"Comma-separated list of user IDs to invite"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Request body parameters"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"channel":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"is_channel":{"type":"boolean"},"is_group":{"type":"boolean"},"is_im":{"type":"boolean"},"is_mpim":{"type":"boolean"},"is_private":{"type":"boolean"},"is_archived":{"type":"boolean"},"is_member":{"type":"boolean"},"created":{"type":"number"},"creator":{"type":"string"},"name_normalized":{"type":"string"},"num_members":{"type":"number"},"topic":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}},"purpose":{"type":"object","properties":{"value":{"type":"string"},"creator":{"type":"string"},"last_set":{"type":"number"}},"additionalProperties":{}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels/{channel}/messages/{timestamp}/reactions":{"post":{"operationId":"slack.add_reaction","description":"Add an emoji reaction to a message. Provide the emoji name without colons.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID containing the message"},"required":true,"description":"Channel ID containing the message"},{"in":"path","name":"timestamp","schema":{"type":"string","description":"Message timestamp to react to"},"required":true,"description":"Message timestamp to react to"},{"in":"query","name":"name","schema":{"type":"string","description":"Emoji name without colons (e.g. thumbsup)"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Request body parameters"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}},"get":{"operationId":"slack.get_reactions","description":"Get all emoji reactions on a specific message in a channel.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID containing the message"},"required":true,"description":"Channel ID containing the message"},{"in":"path","name":"timestamp","schema":{"type":"string","description":"Message timestamp to get reactions for"},"required":true,"description":"Message timestamp to get reactions for"},{"in":"query","name":"full","schema":{"description":"If true, return complete reaction list for each emoji (default false)","type":"boolean"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"type":{"type":"string"},"channel":{"type":"string"},"message":{"type":"object","properties":{"type":{"type":"string"},"text":{"type":"string"},"ts":{"type":"string"},"reactions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"number"},"users":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}},"delete":{"operationId":"slack.remove_reaction","description":"Remove an emoji reaction from a message.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID containing the message"},"required":true,"description":"Channel ID containing the message"},{"in":"path","name":"timestamp","schema":{"type":"string","description":"Message timestamp to remove the reaction from"},"required":true,"description":"Message timestamp to remove the reaction from"},{"in":"query","name":"name","schema":{"type":"string","description":"Emoji name without colons to remove"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels/{channel}/messages/{timestamp}/pins":{"post":{"operationId":"slack.add_pin","description":"Pin a message in a Slack channel.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID containing the message"},"required":true,"description":"Channel ID containing the message"},{"in":"path","name":"timestamp","schema":{"type":"string","description":"Message timestamp to pin"},"required":true,"description":"Message timestamp to pin"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Request body parameters"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}},"delete":{"operationId":"slack.remove_pin","description":"Unpin a message from a Slack channel.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID containing the message"},"required":true,"description":"Channel ID containing the message"},{"in":"path","name":"timestamp","schema":{"type":"string","description":"Message timestamp to unpin"},"required":true,"description":"Message timestamp to unpin"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/channels/{channel}/pins":{"get":{"operationId":"slack.list_pins","description":"List all pinned messages in a Slack channel.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"channel","schema":{"type":"string","description":"Channel ID to list pins for"},"required":true,"description":"Channel ID to list pins for"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"channel":{"type":"string"},"message":{"type":"object","properties":{"type":{"type":"string"},"subtype":{"type":"string"},"text":{"type":"string"},"ts":{"type":"string"},"user":{"type":"string"},"bot_id":{"type":"string"},"thread_ts":{"type":"string"},"reply_count":{"type":"number"},"reply_users_count":{"type":"number"},"latest_reply":{"type":"string"},"reactions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"number"},"users":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}}},"additionalProperties":{}},"created":{"type":"number"},"created_by":{"type":"string"}},"additionalProperties":{}}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/files":{"post":{"operationId":"slack.upload_file","description":"Upload a file to a Slack channel. Supports text content or base64-encoded binary files (xlsx, pdf, images, etc.). Uses the V2 upload API.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"query","name":"channel_id","schema":{"type":"string","description":"Channel ID to upload the file to"}},{"in":"query","name":"filename","schema":{"type":"string","description":"Filename for the uploaded file"}},{"in":"query","name":"content","schema":{"description":"Text content of the file (mutually exclusive with content_base64)","type":"string"}},{"in":"query","name":"content_base64","schema":{"description":"Base64-encoded binary content (mutually exclusive with content). Use for xlsx, pdf, images, etc.","type":"string"}},{"in":"query","name":"initial_comment","schema":{"description":"Message to include with the file upload","type":"string"}},{"in":"query","name":"thread_ts","schema":{"description":"Thread timestamp to upload to (for threaded file shares)","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Request body parameters"}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"files":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"filetype":{"type":"string"},"size":{"type":"number"},"url_private":{"type":"string"},"permalink":{"type":"string"},"created":{"type":"number"}},"additionalProperties":{}}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/users":{"get":{"operationId":"slack.list_users","description":"List all users in the Slack workspace. Returns members with their profiles.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"query","name":"limit","schema":{"description":"Maximum number of items to return per page (default 20, max 999)","type":"string"},"description":"Maximum number of items to return per page (default 20, max 999)"},{"in":"query","name":"cursor","schema":{"description":"Pagination cursor from previous response's response_metadata.next_cursor","type":"string"},"description":"Pagination cursor from previous response's response_metadata.next_cursor"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"real_name":{"type":"string"},"is_bot":{"type":"boolean"},"is_admin":{"type":"boolean"},"is_owner":{"type":"boolean"},"deleted":{"type":"boolean"},"tz":{"type":"string"},"tz_label":{"type":"string"},"profile":{"type":"object","properties":{"real_name":{"type":"string"},"display_name":{"type":"string"},"email":{"type":"string"},"image_72":{"type":"string"},"title":{"type":"string"},"status_text":{"type":"string"},"status_emoji":{"type":"string"}},"additionalProperties":{}}},"additionalProperties":{}}},"response_metadata":{"type":"object","properties":{"next_cursor":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/users/{user}":{"get":{"operationId":"slack.get_user_info","description":"Get detailed information about a Slack user by their user ID.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"path","name":"user","schema":{"type":"string","description":"Slack user ID (e.g. U1234567890)"},"required":true,"description":"Slack user ID (e.g. U1234567890)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"real_name":{"type":"string"},"is_bot":{"type":"boolean"},"is_admin":{"type":"boolean"},"is_owner":{"type":"boolean"},"deleted":{"type":"boolean"},"tz":{"type":"string"},"tz_label":{"type":"string"},"profile":{"type":"object","properties":{"real_name":{"type":"string"},"display_name":{"type":"string"},"email":{"type":"string"},"image_72":{"type":"string"},"title":{"type":"string"},"status_text":{"type":"string"},"status_emoji":{"type":"string"}},"additionalProperties":{}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/api/v1/slack/users/lookup-by-email":{"get":{"operationId":"slack.lookup_user_by_email","description":"Look up a Slack user by their email address. Returns the user's profile.","tags":["slack"],"security":[{"oauth2":[]},{"bearerApiKey":[]}],"parameters":[{"in":"query","name":"email","schema":{"type":"string","description":"Email address to look up"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"real_name":{"type":"string"},"is_bot":{"type":"boolean"},"is_admin":{"type":"boolean"},"is_owner":{"type":"boolean"},"deleted":{"type":"boolean"},"tz":{"type":"string"},"tz_label":{"type":"string"},"profile":{"type":"object","properties":{"real_name":{"type":"string"},"display_name":{"type":"string"},"email":{"type":"string"},"image_72":{"type":"string"},"title":{"type":"string"},"status_text":{"type":"string"},"status_emoji":{"type":"string"}},"additionalProperties":{}}},"additionalProperties":{}}},"required":["ok"],"additionalProperties":{}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}},"502":{"description":"Upstream error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"code":{"type":"string"},"message":{"type":"string"}},"required":["error","code","message"],"additionalProperties":false}}}}}}}},"webhooks":{},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"/oauth/authorize","tokenUrl":"/oauth/token","scopes":{}}}},"bearerApiKey":{"type":"http","scheme":"bearer","description":"API key authentication. Pass a Ferrule API key as a Bearer token."}}}}