archastro.platform.v1.resources.slack_channel_bindings
1# Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License. 2# This file is auto-generated by @archastro/sdk-generator. Do not edit. 3# Content hash: dcc720cd25b2 4 5from __future__ import annotations 6 7import builtins 8from typing import Any, Literal, Required, TypedDict 9 10from pydantic import BaseModel, Field 11 12from ...runtime.http_client import HttpClient, SyncHttpClient 13from ...types.common import ( 14 SlackChannelBinding, 15 SlackChannelBindingListResponse, 16 SlackDeliveryOutcomeListResponse, 17) 18 19 20class SlackChannelBindingCreateInput(TypedDict, total=False): 21 "Create or update a Slack channel binding" 22 23 agent_user_ids: Required[list[str]] 24 "List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents." 25 allow_bot_conversations: bool | None 26 "Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged." 27 channel_id: Required[str] 28 "Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace." 29 customer_label: str | None 30 "Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted." 31 is_ext_shared_cached: bool | None 32 "Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted." 33 is_private_cached: bool | None 34 "Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted." 35 slack_team_id: Required[str] 36 "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use." 37 team_id: Required[str] 38 "ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team." 39 40 41class SlackChannelBindingAssignInput(TypedDict): 42 "Assign a Slack channel's resident agent" 43 44 agent_user_id: str 45 "Agent user ID to assign as the channel's sole resident." 46 channel_id: str 47 "Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none." 48 slack_team_id: str 49 "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use." 50 51 52class SlackChannelBindingProvisionInput(TypedDict, total=False): 53 "Start adding a customer over Slack Connect" 54 55 channel_name: str | None 56 "Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private." 57 customer_email: str | None 58 "Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty." 59 customer_key: Required[str] 60 "The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning." 61 customer_label: Required[str] 62 "Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input." 63 existing_channel_id: str | None 64 "Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`." 65 inputs: dict[str, Any] | None 66 "String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map." 67 slack_team_id: Required[str] 68 "Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts." 69 template_config_id: Required[str] 70 "Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet." 71 72 73class SlackChannelBindingDepositThreadInput(TypedDict, total=False): 74 "Point a Slack channel's deposit pipe at a staging thread, or turn it off" 75 76 slack_team_id: Required[str] 77 "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use." 78 thread_id: str | None 79 "Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off." 80 81 82class SlackChannelBindingDeleteResponse(BaseModel): 83 """ 84 Successful response 85 """ 86 87 channel: str = Field(..., description="Slack channel ID of the binding that was deleted.") 88 deleted: bool = Field( 89 ..., description="Always `true` when the binding was successfully removed." 90 ) 91 92 93class AsyncSlackChannelBindingResource: 94 def __init__(self, http: HttpClient): 95 self._http = http 96 97 async def list( 98 self, 99 *, 100 integration: builtins.list[str] | None = None, 101 team: builtins.list[str] | None = None, 102 agent: builtins.list[str] | None = None, 103 org: builtins.list[str] | None = None, 104 page: int | None = None, 105 per_page: int | None = None, 106 ) -> SlackChannelBindingListResponse: 107 """ 108 List Slack channel bindings 109 Returns a page of Slack channel bindings visible to the authenticated user. 110 Results can be filtered by integration, team, agent, or organization. Omit all 111 filter params to retrieve every binding the caller can see. 112 Pagination is page-based. Pass `page` and `per_page` to navigate large result 113 sets. `page` must be a positive integer; `per_page` must be between 1 and 100. 114 Invalid values return 400. 115 116 Args: 117 integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations. 118 team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams. 119 agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment. 120 org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller. 121 page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer. 122 per_page: Number of bindings to return per page. Defaults to 25; maximum is 100. 123 124 Returns: 125 Paginated list of Slack channel bindings visible to the caller. 126 """ 127 query: dict[str, object] = {} 128 if integration is not None: 129 query["integration"] = integration 130 if team is not None: 131 query["team"] = team 132 if agent is not None: 133 query["agent"] = agent 134 if org is not None: 135 query["org"] = org 136 if page is not None: 137 query["page"] = page 138 if per_page is not None: 139 query["per_page"] = per_page 140 return await self._http.request( 141 "/api/v1/slack_channel_bindings", 142 query=query, 143 response_type=SlackChannelBindingListResponse, 144 ) 145 146 async def create(self, input: SlackChannelBindingCreateInput) -> SlackChannelBinding: 147 """ 148 Create or update a Slack channel binding 149 Creates a new binding between a Slack channel and a team, or updates the 150 existing binding if one already exists for the given channel. The caller also 151 supplies a list of agents to attach to the binding and enroll as members of the 152 destination team. 153 The caller must have team-manage rights on the destination team (and on the 154 currently bound team if the channel is being re-pointed). Returns 403 if 155 permission is insufficient. All write steps are idempotent, so retrying after 156 a partial failure is safe. 157 On success the REST endpoint returns 201 Created. The script binding 158 (`slack.channel_bindings.upsert`) returns the full binding object including the 159 attached agents. 160 161 Args: 162 input: Request body. 163 input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents. 164 input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged. 165 input.channel_id: Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace. 166 input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted. 167 input.is_ext_shared_cached: Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted. 168 input.is_private_cached: Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted. 169 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 170 input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team. 171 172 Returns: 173 The created or updated Slack channel binding, including the full list of currently attached agents. 174 """ 175 return await self._http.request( 176 "/api/v1/slack_channel_bindings", 177 method="POST", 178 body=input, 179 response_type=SlackChannelBinding, 180 ) 181 182 async def assign(self, input: SlackChannelBindingAssignInput) -> SlackChannelBinding: 183 """ 184 Assign a Slack channel's resident agent 185 Makes the given agent the channel's sole resident (one resident per 186 channel: any previously attached agent is detached in the same 187 transaction and its mirror-thread read grant is revoked immediately). 188 Creates a bare internal binding first when the channel has none. 189 Fetches the channel's `is_private` / `is_ext_shared` flags live from 190 Slack (server-side, best-effort) to feed the fail-closed residency 191 gates: a channel shared with an external workspace but not yet bound to 192 a customer team fails with `team_required_for_shared_channel` (bind the 193 team first via `upsert`/setup), and a private channel is member-managed 194 mutation without platform-verified in-channel evidence fails with 195 `channel_membership_required`. 196 When the binding is bound to a customer team, the agent is also 197 enrolled as a member of that team (same pairing as `upsert`). 198 199 Args: 200 input: Request body. 201 input.agent_user_id: Agent user ID to assign as the channel's sole resident. 202 input.channel_id: Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none. 203 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 204 205 Returns: 206 The binding after assignment, with the attached agent list. 207 """ 208 return await self._http.request( 209 "/api/v1/slack_channel_bindings/assign", 210 method="POST", 211 body=input, 212 response_type=SlackChannelBinding, 213 ) 214 215 async def provision(self, input: SlackChannelBindingProvisionInput) -> SlackChannelBinding: 216 """ 217 Start adding a customer over Slack Connect 218 Opens a Slack Connect channel with a new customer creating one and sending 219 the invite, or adopting a shared channel you already have and records who is 220 adding whom so the addition can finish once the customer accepts. 221 The returned binding is **pending**: nothing mirrors, and no per-customer Team, 222 agent, or solution instance exists yet. Acceptance is asynchronous and may 223 never come. When it does, the addition completes in the background under the 224 identity of the admin who called this endpoint, re-checked live at that moment. 225 A caller who has since lost their admin role does not get a substitute the 226 addition is refused and a human re-adds the customer. 227 The caller must be an admin of the Slack integration's own organization. This 228 is the same authority the completion demands, checked here so a customer is 229 never invited into a channel whose addition can never finish. 230 Deliberately not exposed as a script binding: this sends mail to a person 231 outside the org, so it stays a vendor-admin HTTP surface. 232 233 Args: 234 input: Request body. 235 input.channel_name: Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private. 236 input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty. 237 input.customer_key: The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. 238 input.customer_label: Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. 239 input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`. 240 input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map. 241 input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts. 242 input.template_config_id: Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet. 243 244 Returns: 245 The pending binding for the customer's channel. `disclosure_state` is `pending` until the customer accepts, and `scope_key` is null until the addition finishes. 246 """ 247 return await self._http.request( 248 "/api/v1/slack_channel_bindings/provision", 249 method="POST", 250 body=input, 251 response_type=SlackChannelBinding, 252 ) 253 254 async def delete(self, channel: str) -> SlackChannelBindingDeleteResponse: 255 """ 256 Delete a Slack channel binding 257 Removes the binding between a Slack channel and its associated team. The 258 channel is identified by its Slack channel ID together with the `slack_team_id` 259 that scopes it to a specific Slack workspace. Removing the binding does not 260 delete the bound team or any conversation threads scoped to it; decommission 261 those resources separately if required. 262 The caller must have team-manage rights on the team the channel is currently 263 bound to. Returning 403 indicates insufficient permission; returning 404 264 indicates the binding does not exist or is not visible to the caller. 265 The REST endpoint returns 204 No Content on success. The script binding 266 (`slack.channel_bindings.delete`) returns a confirmation object so script 267 callers can verify success without an additional fetch. Both paths are 268 idempotent retrying after a partial failure is safe. 269 270 Args: 271 channel: Slack channel ID of the binding to delete (e.g. `C01234ABCDE`). 272 273 Returns: 274 Successful response 275 """ 276 return await self._http.request( 277 f"/api/v1/slack_channel_bindings/{channel}", 278 method="DELETE", 279 response_type=SlackChannelBindingDeleteResponse, 280 ) 281 282 async def get(self, channel: str, slack_team_id: str) -> SlackChannelBinding: 283 """ 284 Retrieve a Slack channel binding 285 Returns the Slack channel binding identified by a Slack channel ID and workspace 286 team ID pair. Use this endpoint to look up the team and agents currently bound 287 to a specific Slack channel. 288 The `channel` path parameter is the Slack channel ID; `slack_team_id` identifies 289 the Slack workspace the channel belongs to, disambiguating channels with the same 290 ID across workspaces. Both parameters are required. Returns 404 if no binding 291 exists for the given pair or the associated Slack integration is not visible to 292 the caller. 293 294 Args: 295 channel: Slack channel ID of the binding to retrieve (e.g. `C01234ABCDE`). 296 slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding. 297 298 Returns: 299 The Slack channel binding for the given channel and workspace. 300 """ 301 query: dict[str, object] = {} 302 query["slack_team_id"] = slack_team_id 303 return await self._http.request( 304 f"/api/v1/slack_channel_bindings/{channel}", 305 query=query, 306 response_type=SlackChannelBinding, 307 ) 308 309 async def delivery_outcomes( 310 self, 311 channel: str, 312 *, 313 since: str | None = None, 314 outcome: Literal["delivered", "floored", "judge_refused", "failed"] | None = None, 315 limit: int | None = None, 316 before_cursor: str | None = None, 317 after_cursor: str | None = None, 318 ) -> SlackDeliveryOutcomeListResponse: 319 """ 320 List delivery outcomes for a Slack channel 321 Returns what happened to each agent message this platform sent to a Slack 322 channel, newest attempt first. 323 A message that never appears in a Slack channel has several possible causes 324 that look identical from the channel itself: a content guard withheld it, the 325 cross-org judge refused it, Slack rejected the call, or nobody asked anything. 326 This endpoint tells them apart. Use it to confirm a reply was delivered, or to 327 find out why one never arrived, without reading the channel's mirrored 328 conversation. 329 Outcomes cover **outbound agent messages only**. They carry no message 330 content, no author, and nothing about inbound messages. Access follows the 331 channel's binding the organization and app the channel is bound to and 332 needs no membership in the mirrored thread. 333 Paginated with opaque cursors, newest first. When `has_more` is true, pass the 334 response's `before_cursor` back as `before_cursor` to continue into older 335 history. `since` and `outcome` narrow the result set; they are filters, not 336 paging controls. 337 338 Args: 339 channel: Slack channel ID to read delivery outcomes for (e.g. `C01234ABCDE`). 340 since: Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age. 341 outcome: Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld. 342 limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200. 343 before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint. 344 after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row. 345 346 Returns: 347 Delivery outcomes for the requested channel, newest first. 348 """ 349 query: dict[str, object] = {} 350 if since is not None: 351 query["since"] = since 352 if outcome is not None: 353 query["outcome"] = outcome 354 if limit is not None: 355 query["limit"] = limit 356 if before_cursor is not None: 357 query["before_cursor"] = before_cursor 358 if after_cursor is not None: 359 query["after_cursor"] = after_cursor 360 return await self._http.request( 361 f"/api/v1/slack_channel_bindings/{channel}/delivery_outcomes", 362 query=query, 363 response_type=SlackDeliveryOutcomeListResponse, 364 ) 365 366 async def deposit_thread( 367 self, channel: str, input: SlackChannelBindingDepositThreadInput 368 ) -> SlackChannelBinding: 369 """ 370 Point a Slack channel's deposit pipe at a staging thread, or turn it off 371 Sets the binding's deposit target the internal staging thread the 372 deposit pipe copies this channel's mirror content into. Pass a `null` 373 `thread_id` to turn the pipe off. 374 The target is validated server-side: it must exist, belong to the 375 binding's app and org, and never be a Slack mirror thread. Customer 376 bindings (bound `team_id`) additionally require a team-owned private 377 thread with no participant list, so the staging read ACL stays governed 378 by the channel-membership projection. Re-pointing or clearing an 379 existing target purges the old thread's deposit entries. 380 381 Args: 382 channel: Slack channel ID whose binding is being configured (e.g. `C01234ABCDE`). 383 input: Request body. 384 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 385 input.thread_id: Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off. 386 387 Returns: 388 The binding with the updated deposit config. 389 """ 390 return await self._http.request( 391 f"/api/v1/slack_channel_bindings/{channel}/deposit_thread", 392 method="POST", 393 body=input, 394 response_type=SlackChannelBinding, 395 ) 396 397 398class SlackChannelBindingResource: 399 def __init__(self, http: SyncHttpClient): 400 self._http = http 401 402 def list( 403 self, 404 *, 405 integration: builtins.list[str] | None = None, 406 team: builtins.list[str] | None = None, 407 agent: builtins.list[str] | None = None, 408 org: builtins.list[str] | None = None, 409 page: int | None = None, 410 per_page: int | None = None, 411 ) -> SlackChannelBindingListResponse: 412 """ 413 List Slack channel bindings 414 Returns a page of Slack channel bindings visible to the authenticated user. 415 Results can be filtered by integration, team, agent, or organization. Omit all 416 filter params to retrieve every binding the caller can see. 417 Pagination is page-based. Pass `page` and `per_page` to navigate large result 418 sets. `page` must be a positive integer; `per_page` must be between 1 and 100. 419 Invalid values return 400. 420 421 Args: 422 integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations. 423 team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams. 424 agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment. 425 org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller. 426 page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer. 427 per_page: Number of bindings to return per page. Defaults to 25; maximum is 100. 428 429 Returns: 430 Paginated list of Slack channel bindings visible to the caller. 431 """ 432 query: dict[str, object] = {} 433 if integration is not None: 434 query["integration"] = integration 435 if team is not None: 436 query["team"] = team 437 if agent is not None: 438 query["agent"] = agent 439 if org is not None: 440 query["org"] = org 441 if page is not None: 442 query["page"] = page 443 if per_page is not None: 444 query["per_page"] = per_page 445 return self._http.request( 446 "/api/v1/slack_channel_bindings", 447 query=query, 448 response_type=SlackChannelBindingListResponse, 449 ) 450 451 def create(self, input: SlackChannelBindingCreateInput) -> SlackChannelBinding: 452 """ 453 Create or update a Slack channel binding 454 Creates a new binding between a Slack channel and a team, or updates the 455 existing binding if one already exists for the given channel. The caller also 456 supplies a list of agents to attach to the binding and enroll as members of the 457 destination team. 458 The caller must have team-manage rights on the destination team (and on the 459 currently bound team if the channel is being re-pointed). Returns 403 if 460 permission is insufficient. All write steps are idempotent, so retrying after 461 a partial failure is safe. 462 On success the REST endpoint returns 201 Created. The script binding 463 (`slack.channel_bindings.upsert`) returns the full binding object including the 464 attached agents. 465 466 Args: 467 input: Request body. 468 input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents. 469 input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged. 470 input.channel_id: Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace. 471 input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted. 472 input.is_ext_shared_cached: Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted. 473 input.is_private_cached: Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted. 474 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 475 input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team. 476 477 Returns: 478 The created or updated Slack channel binding, including the full list of currently attached agents. 479 """ 480 return self._http.request( 481 "/api/v1/slack_channel_bindings", 482 method="POST", 483 body=input, 484 response_type=SlackChannelBinding, 485 ) 486 487 def assign(self, input: SlackChannelBindingAssignInput) -> SlackChannelBinding: 488 """ 489 Assign a Slack channel's resident agent 490 Makes the given agent the channel's sole resident (one resident per 491 channel: any previously attached agent is detached in the same 492 transaction and its mirror-thread read grant is revoked immediately). 493 Creates a bare internal binding first when the channel has none. 494 Fetches the channel's `is_private` / `is_ext_shared` flags live from 495 Slack (server-side, best-effort) to feed the fail-closed residency 496 gates: a channel shared with an external workspace but not yet bound to 497 a customer team fails with `team_required_for_shared_channel` (bind the 498 team first via `upsert`/setup), and a private channel is member-managed 499 mutation without platform-verified in-channel evidence fails with 500 `channel_membership_required`. 501 When the binding is bound to a customer team, the agent is also 502 enrolled as a member of that team (same pairing as `upsert`). 503 504 Args: 505 input: Request body. 506 input.agent_user_id: Agent user ID to assign as the channel's sole resident. 507 input.channel_id: Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none. 508 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 509 510 Returns: 511 The binding after assignment, with the attached agent list. 512 """ 513 return self._http.request( 514 "/api/v1/slack_channel_bindings/assign", 515 method="POST", 516 body=input, 517 response_type=SlackChannelBinding, 518 ) 519 520 def provision(self, input: SlackChannelBindingProvisionInput) -> SlackChannelBinding: 521 """ 522 Start adding a customer over Slack Connect 523 Opens a Slack Connect channel with a new customer creating one and sending 524 the invite, or adopting a shared channel you already have and records who is 525 adding whom so the addition can finish once the customer accepts. 526 The returned binding is **pending**: nothing mirrors, and no per-customer Team, 527 agent, or solution instance exists yet. Acceptance is asynchronous and may 528 never come. When it does, the addition completes in the background under the 529 identity of the admin who called this endpoint, re-checked live at that moment. 530 A caller who has since lost their admin role does not get a substitute the 531 addition is refused and a human re-adds the customer. 532 The caller must be an admin of the Slack integration's own organization. This 533 is the same authority the completion demands, checked here so a customer is 534 never invited into a channel whose addition can never finish. 535 Deliberately not exposed as a script binding: this sends mail to a person 536 outside the org, so it stays a vendor-admin HTTP surface. 537 538 Args: 539 input: Request body. 540 input.channel_name: Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private. 541 input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty. 542 input.customer_key: The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. 543 input.customer_label: Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. 544 input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`. 545 input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map. 546 input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts. 547 input.template_config_id: Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet. 548 549 Returns: 550 The pending binding for the customer's channel. `disclosure_state` is `pending` until the customer accepts, and `scope_key` is null until the addition finishes. 551 """ 552 return self._http.request( 553 "/api/v1/slack_channel_bindings/provision", 554 method="POST", 555 body=input, 556 response_type=SlackChannelBinding, 557 ) 558 559 def delete(self, channel: str) -> SlackChannelBindingDeleteResponse: 560 """ 561 Delete a Slack channel binding 562 Removes the binding between a Slack channel and its associated team. The 563 channel is identified by its Slack channel ID together with the `slack_team_id` 564 that scopes it to a specific Slack workspace. Removing the binding does not 565 delete the bound team or any conversation threads scoped to it; decommission 566 those resources separately if required. 567 The caller must have team-manage rights on the team the channel is currently 568 bound to. Returning 403 indicates insufficient permission; returning 404 569 indicates the binding does not exist or is not visible to the caller. 570 The REST endpoint returns 204 No Content on success. The script binding 571 (`slack.channel_bindings.delete`) returns a confirmation object so script 572 callers can verify success without an additional fetch. Both paths are 573 idempotent retrying after a partial failure is safe. 574 575 Args: 576 channel: Slack channel ID of the binding to delete (e.g. `C01234ABCDE`). 577 578 Returns: 579 Successful response 580 """ 581 return self._http.request( 582 f"/api/v1/slack_channel_bindings/{channel}", 583 method="DELETE", 584 response_type=SlackChannelBindingDeleteResponse, 585 ) 586 587 def get(self, channel: str, slack_team_id: str) -> SlackChannelBinding: 588 """ 589 Retrieve a Slack channel binding 590 Returns the Slack channel binding identified by a Slack channel ID and workspace 591 team ID pair. Use this endpoint to look up the team and agents currently bound 592 to a specific Slack channel. 593 The `channel` path parameter is the Slack channel ID; `slack_team_id` identifies 594 the Slack workspace the channel belongs to, disambiguating channels with the same 595 ID across workspaces. Both parameters are required. Returns 404 if no binding 596 exists for the given pair or the associated Slack integration is not visible to 597 the caller. 598 599 Args: 600 channel: Slack channel ID of the binding to retrieve (e.g. `C01234ABCDE`). 601 slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding. 602 603 Returns: 604 The Slack channel binding for the given channel and workspace. 605 """ 606 query: dict[str, object] = {} 607 query["slack_team_id"] = slack_team_id 608 return self._http.request( 609 f"/api/v1/slack_channel_bindings/{channel}", 610 query=query, 611 response_type=SlackChannelBinding, 612 ) 613 614 def delivery_outcomes( 615 self, 616 channel: str, 617 *, 618 since: str | None = None, 619 outcome: Literal["delivered", "floored", "judge_refused", "failed"] | None = None, 620 limit: int | None = None, 621 before_cursor: str | None = None, 622 after_cursor: str | None = None, 623 ) -> SlackDeliveryOutcomeListResponse: 624 """ 625 List delivery outcomes for a Slack channel 626 Returns what happened to each agent message this platform sent to a Slack 627 channel, newest attempt first. 628 A message that never appears in a Slack channel has several possible causes 629 that look identical from the channel itself: a content guard withheld it, the 630 cross-org judge refused it, Slack rejected the call, or nobody asked anything. 631 This endpoint tells them apart. Use it to confirm a reply was delivered, or to 632 find out why one never arrived, without reading the channel's mirrored 633 conversation. 634 Outcomes cover **outbound agent messages only**. They carry no message 635 content, no author, and nothing about inbound messages. Access follows the 636 channel's binding the organization and app the channel is bound to and 637 needs no membership in the mirrored thread. 638 Paginated with opaque cursors, newest first. When `has_more` is true, pass the 639 response's `before_cursor` back as `before_cursor` to continue into older 640 history. `since` and `outcome` narrow the result set; they are filters, not 641 paging controls. 642 643 Args: 644 channel: Slack channel ID to read delivery outcomes for (e.g. `C01234ABCDE`). 645 since: Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age. 646 outcome: Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld. 647 limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200. 648 before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint. 649 after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row. 650 651 Returns: 652 Delivery outcomes for the requested channel, newest first. 653 """ 654 query: dict[str, object] = {} 655 if since is not None: 656 query["since"] = since 657 if outcome is not None: 658 query["outcome"] = outcome 659 if limit is not None: 660 query["limit"] = limit 661 if before_cursor is not None: 662 query["before_cursor"] = before_cursor 663 if after_cursor is not None: 664 query["after_cursor"] = after_cursor 665 return self._http.request( 666 f"/api/v1/slack_channel_bindings/{channel}/delivery_outcomes", 667 query=query, 668 response_type=SlackDeliveryOutcomeListResponse, 669 ) 670 671 def deposit_thread( 672 self, channel: str, input: SlackChannelBindingDepositThreadInput 673 ) -> SlackChannelBinding: 674 """ 675 Point a Slack channel's deposit pipe at a staging thread, or turn it off 676 Sets the binding's deposit target the internal staging thread the 677 deposit pipe copies this channel's mirror content into. Pass a `null` 678 `thread_id` to turn the pipe off. 679 The target is validated server-side: it must exist, belong to the 680 binding's app and org, and never be a Slack mirror thread. Customer 681 bindings (bound `team_id`) additionally require a team-owned private 682 thread with no participant list, so the staging read ACL stays governed 683 by the channel-membership projection. Re-pointing or clearing an 684 existing target purges the old thread's deposit entries. 685 686 Args: 687 channel: Slack channel ID whose binding is being configured (e.g. `C01234ABCDE`). 688 input: Request body. 689 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 690 input.thread_id: Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off. 691 692 Returns: 693 The binding with the updated deposit config. 694 """ 695 return self._http.request( 696 f"/api/v1/slack_channel_bindings/{channel}/deposit_thread", 697 method="POST", 698 body=input, 699 response_type=SlackChannelBinding, 700 )
21class SlackChannelBindingCreateInput(TypedDict, total=False): 22 "Create or update a Slack channel binding" 23 24 agent_user_ids: Required[list[str]] 25 "List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents." 26 allow_bot_conversations: bool | None 27 "Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged." 28 channel_id: Required[str] 29 "Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace." 30 customer_label: str | None 31 "Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted." 32 is_ext_shared_cached: bool | None 33 "Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted." 34 is_private_cached: bool | None 35 "Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted." 36 slack_team_id: Required[str] 37 "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use." 38 team_id: Required[str] 39 "ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team."
Create or update a Slack channel binding
List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents.
Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged.
Slack channel ID to bind (e.g. C01234ABCDE). Acts as the natural key of the binding within the workspace.
Human-readable label for the customer associated with this channel. Stored in the binding's config. null if omitted.
Cached value of Slack's is_private flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. null if omitted.
42class SlackChannelBindingAssignInput(TypedDict): 43 "Assign a Slack channel's resident agent" 44 45 agent_user_id: str 46 "Agent user ID to assign as the channel's sole resident." 47 channel_id: str 48 "Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none." 49 slack_team_id: str 50 "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use."
Assign a Slack channel's resident agent
53class SlackChannelBindingProvisionInput(TypedDict, total=False): 54 "Start adding a customer over Slack Connect" 55 56 channel_name: str | None 57 "Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private." 58 customer_email: str | None 59 "Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty." 60 customer_key: Required[str] 61 "The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning." 62 customer_label: Required[str] 63 "Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input." 64 existing_channel_id: str | None 65 "Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`." 66 inputs: dict[str, Any] | None 67 "String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map." 68 slack_team_id: Required[str] 69 "Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts." 70 template_config_id: Required[str] 71 "Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet."
Start adding a customer over Slack Connect
Name for a Slack channel to create for this customer. Required unless existing_channel_id is given. The channel is created private.
Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty.
The vendor's own primary key for this customer (customer_id / account_id / tenant_id). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning.
Human-readable name for the customer (e.g. Acme, Inc.). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input.
Adopt this already-shared Slack Connect channel (e.g. C01234ABCDE) instead of creating one. Mutually exclusive with channel_name.
String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map.
74class SlackChannelBindingDepositThreadInput(TypedDict, total=False): 75 "Point a Slack channel's deposit pipe at a staging thread, or turn it off" 76 77 slack_team_id: Required[str] 78 "Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use." 79 thread_id: str | None 80 "Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off."
Point a Slack channel's deposit pipe at a staging thread, or turn it off
83class SlackChannelBindingDeleteResponse(BaseModel): 84 """ 85 Successful response 86 """ 87 88 channel: str = Field(..., description="Slack channel ID of the binding that was deleted.") 89 deleted: bool = Field( 90 ..., description="Always `true` when the binding was successfully removed." 91 )
Successful response
94class AsyncSlackChannelBindingResource: 95 def __init__(self, http: HttpClient): 96 self._http = http 97 98 async def list( 99 self, 100 *, 101 integration: builtins.list[str] | None = None, 102 team: builtins.list[str] | None = None, 103 agent: builtins.list[str] | None = None, 104 org: builtins.list[str] | None = None, 105 page: int | None = None, 106 per_page: int | None = None, 107 ) -> SlackChannelBindingListResponse: 108 """ 109 List Slack channel bindings 110 Returns a page of Slack channel bindings visible to the authenticated user. 111 Results can be filtered by integration, team, agent, or organization. Omit all 112 filter params to retrieve every binding the caller can see. 113 Pagination is page-based. Pass `page` and `per_page` to navigate large result 114 sets. `page` must be a positive integer; `per_page` must be between 1 and 100. 115 Invalid values return 400. 116 117 Args: 118 integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations. 119 team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams. 120 agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment. 121 org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller. 122 page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer. 123 per_page: Number of bindings to return per page. Defaults to 25; maximum is 100. 124 125 Returns: 126 Paginated list of Slack channel bindings visible to the caller. 127 """ 128 query: dict[str, object] = {} 129 if integration is not None: 130 query["integration"] = integration 131 if team is not None: 132 query["team"] = team 133 if agent is not None: 134 query["agent"] = agent 135 if org is not None: 136 query["org"] = org 137 if page is not None: 138 query["page"] = page 139 if per_page is not None: 140 query["per_page"] = per_page 141 return await self._http.request( 142 "/api/v1/slack_channel_bindings", 143 query=query, 144 response_type=SlackChannelBindingListResponse, 145 ) 146 147 async def create(self, input: SlackChannelBindingCreateInput) -> SlackChannelBinding: 148 """ 149 Create or update a Slack channel binding 150 Creates a new binding between a Slack channel and a team, or updates the 151 existing binding if one already exists for the given channel. The caller also 152 supplies a list of agents to attach to the binding and enroll as members of the 153 destination team. 154 The caller must have team-manage rights on the destination team (and on the 155 currently bound team if the channel is being re-pointed). Returns 403 if 156 permission is insufficient. All write steps are idempotent, so retrying after 157 a partial failure is safe. 158 On success the REST endpoint returns 201 Created. The script binding 159 (`slack.channel_bindings.upsert`) returns the full binding object including the 160 attached agents. 161 162 Args: 163 input: Request body. 164 input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents. 165 input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged. 166 input.channel_id: Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace. 167 input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted. 168 input.is_ext_shared_cached: Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted. 169 input.is_private_cached: Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted. 170 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 171 input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team. 172 173 Returns: 174 The created or updated Slack channel binding, including the full list of currently attached agents. 175 """ 176 return await self._http.request( 177 "/api/v1/slack_channel_bindings", 178 method="POST", 179 body=input, 180 response_type=SlackChannelBinding, 181 ) 182 183 async def assign(self, input: SlackChannelBindingAssignInput) -> SlackChannelBinding: 184 """ 185 Assign a Slack channel's resident agent 186 Makes the given agent the channel's sole resident (one resident per 187 channel: any previously attached agent is detached in the same 188 transaction and its mirror-thread read grant is revoked immediately). 189 Creates a bare internal binding first when the channel has none. 190 Fetches the channel's `is_private` / `is_ext_shared` flags live from 191 Slack (server-side, best-effort) to feed the fail-closed residency 192 gates: a channel shared with an external workspace but not yet bound to 193 a customer team fails with `team_required_for_shared_channel` (bind the 194 team first via `upsert`/setup), and a private channel is member-managed 195 mutation without platform-verified in-channel evidence fails with 196 `channel_membership_required`. 197 When the binding is bound to a customer team, the agent is also 198 enrolled as a member of that team (same pairing as `upsert`). 199 200 Args: 201 input: Request body. 202 input.agent_user_id: Agent user ID to assign as the channel's sole resident. 203 input.channel_id: Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none. 204 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 205 206 Returns: 207 The binding after assignment, with the attached agent list. 208 """ 209 return await self._http.request( 210 "/api/v1/slack_channel_bindings/assign", 211 method="POST", 212 body=input, 213 response_type=SlackChannelBinding, 214 ) 215 216 async def provision(self, input: SlackChannelBindingProvisionInput) -> SlackChannelBinding: 217 """ 218 Start adding a customer over Slack Connect 219 Opens a Slack Connect channel with a new customer creating one and sending 220 the invite, or adopting a shared channel you already have and records who is 221 adding whom so the addition can finish once the customer accepts. 222 The returned binding is **pending**: nothing mirrors, and no per-customer Team, 223 agent, or solution instance exists yet. Acceptance is asynchronous and may 224 never come. When it does, the addition completes in the background under the 225 identity of the admin who called this endpoint, re-checked live at that moment. 226 A caller who has since lost their admin role does not get a substitute the 227 addition is refused and a human re-adds the customer. 228 The caller must be an admin of the Slack integration's own organization. This 229 is the same authority the completion demands, checked here so a customer is 230 never invited into a channel whose addition can never finish. 231 Deliberately not exposed as a script binding: this sends mail to a person 232 outside the org, so it stays a vendor-admin HTTP surface. 233 234 Args: 235 input: Request body. 236 input.channel_name: Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private. 237 input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty. 238 input.customer_key: The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. 239 input.customer_label: Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. 240 input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`. 241 input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map. 242 input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts. 243 input.template_config_id: Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet. 244 245 Returns: 246 The pending binding for the customer's channel. `disclosure_state` is `pending` until the customer accepts, and `scope_key` is null until the addition finishes. 247 """ 248 return await self._http.request( 249 "/api/v1/slack_channel_bindings/provision", 250 method="POST", 251 body=input, 252 response_type=SlackChannelBinding, 253 ) 254 255 async def delete(self, channel: str) -> SlackChannelBindingDeleteResponse: 256 """ 257 Delete a Slack channel binding 258 Removes the binding between a Slack channel and its associated team. The 259 channel is identified by its Slack channel ID together with the `slack_team_id` 260 that scopes it to a specific Slack workspace. Removing the binding does not 261 delete the bound team or any conversation threads scoped to it; decommission 262 those resources separately if required. 263 The caller must have team-manage rights on the team the channel is currently 264 bound to. Returning 403 indicates insufficient permission; returning 404 265 indicates the binding does not exist or is not visible to the caller. 266 The REST endpoint returns 204 No Content on success. The script binding 267 (`slack.channel_bindings.delete`) returns a confirmation object so script 268 callers can verify success without an additional fetch. Both paths are 269 idempotent retrying after a partial failure is safe. 270 271 Args: 272 channel: Slack channel ID of the binding to delete (e.g. `C01234ABCDE`). 273 274 Returns: 275 Successful response 276 """ 277 return await self._http.request( 278 f"/api/v1/slack_channel_bindings/{channel}", 279 method="DELETE", 280 response_type=SlackChannelBindingDeleteResponse, 281 ) 282 283 async def get(self, channel: str, slack_team_id: str) -> SlackChannelBinding: 284 """ 285 Retrieve a Slack channel binding 286 Returns the Slack channel binding identified by a Slack channel ID and workspace 287 team ID pair. Use this endpoint to look up the team and agents currently bound 288 to a specific Slack channel. 289 The `channel` path parameter is the Slack channel ID; `slack_team_id` identifies 290 the Slack workspace the channel belongs to, disambiguating channels with the same 291 ID across workspaces. Both parameters are required. Returns 404 if no binding 292 exists for the given pair or the associated Slack integration is not visible to 293 the caller. 294 295 Args: 296 channel: Slack channel ID of the binding to retrieve (e.g. `C01234ABCDE`). 297 slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding. 298 299 Returns: 300 The Slack channel binding for the given channel and workspace. 301 """ 302 query: dict[str, object] = {} 303 query["slack_team_id"] = slack_team_id 304 return await self._http.request( 305 f"/api/v1/slack_channel_bindings/{channel}", 306 query=query, 307 response_type=SlackChannelBinding, 308 ) 309 310 async def delivery_outcomes( 311 self, 312 channel: str, 313 *, 314 since: str | None = None, 315 outcome: Literal["delivered", "floored", "judge_refused", "failed"] | None = None, 316 limit: int | None = None, 317 before_cursor: str | None = None, 318 after_cursor: str | None = None, 319 ) -> SlackDeliveryOutcomeListResponse: 320 """ 321 List delivery outcomes for a Slack channel 322 Returns what happened to each agent message this platform sent to a Slack 323 channel, newest attempt first. 324 A message that never appears in a Slack channel has several possible causes 325 that look identical from the channel itself: a content guard withheld it, the 326 cross-org judge refused it, Slack rejected the call, or nobody asked anything. 327 This endpoint tells them apart. Use it to confirm a reply was delivered, or to 328 find out why one never arrived, without reading the channel's mirrored 329 conversation. 330 Outcomes cover **outbound agent messages only**. They carry no message 331 content, no author, and nothing about inbound messages. Access follows the 332 channel's binding the organization and app the channel is bound to and 333 needs no membership in the mirrored thread. 334 Paginated with opaque cursors, newest first. When `has_more` is true, pass the 335 response's `before_cursor` back as `before_cursor` to continue into older 336 history. `since` and `outcome` narrow the result set; they are filters, not 337 paging controls. 338 339 Args: 340 channel: Slack channel ID to read delivery outcomes for (e.g. `C01234ABCDE`). 341 since: Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age. 342 outcome: Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld. 343 limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200. 344 before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint. 345 after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row. 346 347 Returns: 348 Delivery outcomes for the requested channel, newest first. 349 """ 350 query: dict[str, object] = {} 351 if since is not None: 352 query["since"] = since 353 if outcome is not None: 354 query["outcome"] = outcome 355 if limit is not None: 356 query["limit"] = limit 357 if before_cursor is not None: 358 query["before_cursor"] = before_cursor 359 if after_cursor is not None: 360 query["after_cursor"] = after_cursor 361 return await self._http.request( 362 f"/api/v1/slack_channel_bindings/{channel}/delivery_outcomes", 363 query=query, 364 response_type=SlackDeliveryOutcomeListResponse, 365 ) 366 367 async def deposit_thread( 368 self, channel: str, input: SlackChannelBindingDepositThreadInput 369 ) -> SlackChannelBinding: 370 """ 371 Point a Slack channel's deposit pipe at a staging thread, or turn it off 372 Sets the binding's deposit target the internal staging thread the 373 deposit pipe copies this channel's mirror content into. Pass a `null` 374 `thread_id` to turn the pipe off. 375 The target is validated server-side: it must exist, belong to the 376 binding's app and org, and never be a Slack mirror thread. Customer 377 bindings (bound `team_id`) additionally require a team-owned private 378 thread with no participant list, so the staging read ACL stays governed 379 by the channel-membership projection. Re-pointing or clearing an 380 existing target purges the old thread's deposit entries. 381 382 Args: 383 channel: Slack channel ID whose binding is being configured (e.g. `C01234ABCDE`). 384 input: Request body. 385 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 386 input.thread_id: Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off. 387 388 Returns: 389 The binding with the updated deposit config. 390 """ 391 return await self._http.request( 392 f"/api/v1/slack_channel_bindings/{channel}/deposit_thread", 393 method="POST", 394 body=input, 395 response_type=SlackChannelBinding, 396 )
98 async def list( 99 self, 100 *, 101 integration: builtins.list[str] | None = None, 102 team: builtins.list[str] | None = None, 103 agent: builtins.list[str] | None = None, 104 org: builtins.list[str] | None = None, 105 page: int | None = None, 106 per_page: int | None = None, 107 ) -> SlackChannelBindingListResponse: 108 """ 109 List Slack channel bindings 110 Returns a page of Slack channel bindings visible to the authenticated user. 111 Results can be filtered by integration, team, agent, or organization. Omit all 112 filter params to retrieve every binding the caller can see. 113 Pagination is page-based. Pass `page` and `per_page` to navigate large result 114 sets. `page` must be a positive integer; `per_page` must be between 1 and 100. 115 Invalid values return 400. 116 117 Args: 118 integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations. 119 team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams. 120 agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment. 121 org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller. 122 page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer. 123 per_page: Number of bindings to return per page. Defaults to 25; maximum is 100. 124 125 Returns: 126 Paginated list of Slack channel bindings visible to the caller. 127 """ 128 query: dict[str, object] = {} 129 if integration is not None: 130 query["integration"] = integration 131 if team is not None: 132 query["team"] = team 133 if agent is not None: 134 query["agent"] = agent 135 if org is not None: 136 query["org"] = org 137 if page is not None: 138 query["page"] = page 139 if per_page is not None: 140 query["per_page"] = per_page 141 return await self._http.request( 142 "/api/v1/slack_channel_bindings", 143 query=query, 144 response_type=SlackChannelBindingListResponse, 145 )
List Slack channel bindings
Returns a page of Slack channel bindings visible to the authenticated user.
Results can be filtered by integration, team, agent, or organization. Omit all
filter params to retrieve every binding the caller can see.
Pagination is page-based. Pass page and per_page to navigate large result
sets. page must be a positive integer; per_page must be between 1 and 100.
Invalid values return 400.
Arguments:
- integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations.
- team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams.
- agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment.
- org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller.
- page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer.
- per_page: Number of bindings to return per page. Defaults to 25; maximum is 100.
Returns:
Paginated list of Slack channel bindings visible to the caller.
147 async def create(self, input: SlackChannelBindingCreateInput) -> SlackChannelBinding: 148 """ 149 Create or update a Slack channel binding 150 Creates a new binding between a Slack channel and a team, or updates the 151 existing binding if one already exists for the given channel. The caller also 152 supplies a list of agents to attach to the binding and enroll as members of the 153 destination team. 154 The caller must have team-manage rights on the destination team (and on the 155 currently bound team if the channel is being re-pointed). Returns 403 if 156 permission is insufficient. All write steps are idempotent, so retrying after 157 a partial failure is safe. 158 On success the REST endpoint returns 201 Created. The script binding 159 (`slack.channel_bindings.upsert`) returns the full binding object including the 160 attached agents. 161 162 Args: 163 input: Request body. 164 input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents. 165 input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged. 166 input.channel_id: Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace. 167 input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted. 168 input.is_ext_shared_cached: Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted. 169 input.is_private_cached: Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted. 170 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 171 input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team. 172 173 Returns: 174 The created or updated Slack channel binding, including the full list of currently attached agents. 175 """ 176 return await self._http.request( 177 "/api/v1/slack_channel_bindings", 178 method="POST", 179 body=input, 180 response_type=SlackChannelBinding, 181 )
Create or update a Slack channel binding
Creates a new binding between a Slack channel and a team, or updates the
existing binding if one already exists for the given channel. The caller also
supplies a list of agents to attach to the binding and enroll as members of the
destination team.
The caller must have team-manage rights on the destination team (and on the
currently bound team if the channel is being re-pointed). Returns 403 if
permission is insufficient. All write steps are idempotent, so retrying after
a partial failure is safe.
On success the REST endpoint returns 201 Created. The script binding
(slack.channel_bindings.upsert) returns the full binding object including the
attached agents.
Arguments:
- input: Request body.
- input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents.
- input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged.
- input.channel_id: Slack channel ID to bind (e.g.
C01234ABCDE). Acts as the natural key of the binding within the workspace. - input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config.
nullif omitted. - input.is_ext_shared_cached: Cached value of Slack's
is_ext_sharedflag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups.nullif omitted. - input.is_private_cached: Cached value of Slack's
is_privateflag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed.nullif omitted. - input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Identifies which Slack integration to use. - input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team.
Returns:
The created or updated Slack channel binding, including the full list of currently attached agents.
183 async def assign(self, input: SlackChannelBindingAssignInput) -> SlackChannelBinding: 184 """ 185 Assign a Slack channel's resident agent 186 Makes the given agent the channel's sole resident (one resident per 187 channel: any previously attached agent is detached in the same 188 transaction and its mirror-thread read grant is revoked immediately). 189 Creates a bare internal binding first when the channel has none. 190 Fetches the channel's `is_private` / `is_ext_shared` flags live from 191 Slack (server-side, best-effort) to feed the fail-closed residency 192 gates: a channel shared with an external workspace but not yet bound to 193 a customer team fails with `team_required_for_shared_channel` (bind the 194 team first via `upsert`/setup), and a private channel is member-managed 195 mutation without platform-verified in-channel evidence fails with 196 `channel_membership_required`. 197 When the binding is bound to a customer team, the agent is also 198 enrolled as a member of that team (same pairing as `upsert`). 199 200 Args: 201 input: Request body. 202 input.agent_user_id: Agent user ID to assign as the channel's sole resident. 203 input.channel_id: Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none. 204 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 205 206 Returns: 207 The binding after assignment, with the attached agent list. 208 """ 209 return await self._http.request( 210 "/api/v1/slack_channel_bindings/assign", 211 method="POST", 212 body=input, 213 response_type=SlackChannelBinding, 214 )
Assign a Slack channel's resident agent
Makes the given agent the channel's sole resident (one resident per
channel: any previously attached agent is detached in the same
transaction and its mirror-thread read grant is revoked immediately).
Creates a bare internal binding first when the channel has none.
Fetches the channel's is_private / is_ext_shared flags live from
Slack (server-side, best-effort) to feed the fail-closed residency
gates: a channel shared with an external workspace but not yet bound to
a customer team fails with team_required_for_shared_channel (bind the
team first via upsert/setup), and a private channel is member-managed
mutation without platform-verified in-channel evidence fails with
channel_membership_required.
When the binding is bound to a customer team, the agent is also
enrolled as a member of that team (same pairing as upsert).
Arguments:
- input: Request body.
- input.agent_user_id: Agent user ID to assign as the channel's sole resident.
- input.channel_id: Slack channel ID whose resident is being assigned (e.g.
C01234ABCDE). A bare internal binding is created when the channel has none. - input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Identifies which Slack integration to use.
Returns:
The binding after assignment, with the attached agent list.
216 async def provision(self, input: SlackChannelBindingProvisionInput) -> SlackChannelBinding: 217 """ 218 Start adding a customer over Slack Connect 219 Opens a Slack Connect channel with a new customer creating one and sending 220 the invite, or adopting a shared channel you already have and records who is 221 adding whom so the addition can finish once the customer accepts. 222 The returned binding is **pending**: nothing mirrors, and no per-customer Team, 223 agent, or solution instance exists yet. Acceptance is asynchronous and may 224 never come. When it does, the addition completes in the background under the 225 identity of the admin who called this endpoint, re-checked live at that moment. 226 A caller who has since lost their admin role does not get a substitute the 227 addition is refused and a human re-adds the customer. 228 The caller must be an admin of the Slack integration's own organization. This 229 is the same authority the completion demands, checked here so a customer is 230 never invited into a channel whose addition can never finish. 231 Deliberately not exposed as a script binding: this sends mail to a person 232 outside the org, so it stays a vendor-admin HTTP surface. 233 234 Args: 235 input: Request body. 236 input.channel_name: Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private. 237 input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty. 238 input.customer_key: The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. 239 input.customer_label: Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. 240 input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`. 241 input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map. 242 input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts. 243 input.template_config_id: Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet. 244 245 Returns: 246 The pending binding for the customer's channel. `disclosure_state` is `pending` until the customer accepts, and `scope_key` is null until the addition finishes. 247 """ 248 return await self._http.request( 249 "/api/v1/slack_channel_bindings/provision", 250 method="POST", 251 body=input, 252 response_type=SlackChannelBinding, 253 )
Start adding a customer over Slack Connect Opens a Slack Connect channel with a new customer creating one and sending the invite, or adopting a shared channel you already have and records who is adding whom so the addition can finish once the customer accepts. The returned binding is pending: nothing mirrors, and no per-customer Team, agent, or solution instance exists yet. Acceptance is asynchronous and may never come. When it does, the addition completes in the background under the identity of the admin who called this endpoint, re-checked live at that moment. A caller who has since lost their admin role does not get a substitute the addition is refused and a human re-adds the customer. The caller must be an admin of the Slack integration's own organization. This is the same authority the completion demands, checked here so a customer is never invited into a channel whose addition can never finish. Deliberately not exposed as a script binding: this sends mail to a person outside the org, so it stays a vendor-admin HTTP surface.
Arguments:
- input: Request body.
- input.channel_name: Name for a Slack channel to create for this customer. Required unless
existing_channel_idis given. The channel is created private. - input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty.
- input.customer_key: The vendor's own primary key for this customer (
customer_id/account_id/tenant_id). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. - input.customer_label: Human-readable name for the customer (e.g.
Acme, Inc.). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. - input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g.
C01234ABCDE) instead of creating one. Mutually exclusive withchannel_name. - input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map.
- input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g.
T01234ABCDE). The customer's workspace is not known yet it resolves from whoever accepts. - input.template_config_id: Config ID (
cfg_) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet.
Returns:
The pending binding for the customer's channel.
disclosure_stateispendinguntil the customer accepts, andscope_keyis null until the addition finishes.
255 async def delete(self, channel: str) -> SlackChannelBindingDeleteResponse: 256 """ 257 Delete a Slack channel binding 258 Removes the binding between a Slack channel and its associated team. The 259 channel is identified by its Slack channel ID together with the `slack_team_id` 260 that scopes it to a specific Slack workspace. Removing the binding does not 261 delete the bound team or any conversation threads scoped to it; decommission 262 those resources separately if required. 263 The caller must have team-manage rights on the team the channel is currently 264 bound to. Returning 403 indicates insufficient permission; returning 404 265 indicates the binding does not exist or is not visible to the caller. 266 The REST endpoint returns 204 No Content on success. The script binding 267 (`slack.channel_bindings.delete`) returns a confirmation object so script 268 callers can verify success without an additional fetch. Both paths are 269 idempotent retrying after a partial failure is safe. 270 271 Args: 272 channel: Slack channel ID of the binding to delete (e.g. `C01234ABCDE`). 273 274 Returns: 275 Successful response 276 """ 277 return await self._http.request( 278 f"/api/v1/slack_channel_bindings/{channel}", 279 method="DELETE", 280 response_type=SlackChannelBindingDeleteResponse, 281 )
Delete a Slack channel binding
Removes the binding between a Slack channel and its associated team. The
channel is identified by its Slack channel ID together with the slack_team_id
that scopes it to a specific Slack workspace. Removing the binding does not
delete the bound team or any conversation threads scoped to it; decommission
those resources separately if required.
The caller must have team-manage rights on the team the channel is currently
bound to. Returning 403 indicates insufficient permission; returning 404
indicates the binding does not exist or is not visible to the caller.
The REST endpoint returns 204 No Content on success. The script binding
(slack.channel_bindings.delete) returns a confirmation object so script
callers can verify success without an additional fetch. Both paths are
idempotent retrying after a partial failure is safe.
Arguments:
- channel: Slack channel ID of the binding to delete (e.g.
C01234ABCDE).
Returns:
Successful response
283 async def get(self, channel: str, slack_team_id: str) -> SlackChannelBinding: 284 """ 285 Retrieve a Slack channel binding 286 Returns the Slack channel binding identified by a Slack channel ID and workspace 287 team ID pair. Use this endpoint to look up the team and agents currently bound 288 to a specific Slack channel. 289 The `channel` path parameter is the Slack channel ID; `slack_team_id` identifies 290 the Slack workspace the channel belongs to, disambiguating channels with the same 291 ID across workspaces. Both parameters are required. Returns 404 if no binding 292 exists for the given pair or the associated Slack integration is not visible to 293 the caller. 294 295 Args: 296 channel: Slack channel ID of the binding to retrieve (e.g. `C01234ABCDE`). 297 slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding. 298 299 Returns: 300 The Slack channel binding for the given channel and workspace. 301 """ 302 query: dict[str, object] = {} 303 query["slack_team_id"] = slack_team_id 304 return await self._http.request( 305 f"/api/v1/slack_channel_bindings/{channel}", 306 query=query, 307 response_type=SlackChannelBinding, 308 )
Retrieve a Slack channel binding
Returns the Slack channel binding identified by a Slack channel ID and workspace
team ID pair. Use this endpoint to look up the team and agents currently bound
to a specific Slack channel.
The channel path parameter is the Slack channel ID; slack_team_id identifies
the Slack workspace the channel belongs to, disambiguating channels with the same
ID across workspaces. Both parameters are required. Returns 404 if no binding
exists for the given pair or the associated Slack integration is not visible to
the caller.
Arguments:
- channel: Slack channel ID of the binding to retrieve (e.g.
C01234ABCDE). - slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Used together withchannelto uniquely identify the binding.
Returns:
The Slack channel binding for the given channel and workspace.
310 async def delivery_outcomes( 311 self, 312 channel: str, 313 *, 314 since: str | None = None, 315 outcome: Literal["delivered", "floored", "judge_refused", "failed"] | None = None, 316 limit: int | None = None, 317 before_cursor: str | None = None, 318 after_cursor: str | None = None, 319 ) -> SlackDeliveryOutcomeListResponse: 320 """ 321 List delivery outcomes for a Slack channel 322 Returns what happened to each agent message this platform sent to a Slack 323 channel, newest attempt first. 324 A message that never appears in a Slack channel has several possible causes 325 that look identical from the channel itself: a content guard withheld it, the 326 cross-org judge refused it, Slack rejected the call, or nobody asked anything. 327 This endpoint tells them apart. Use it to confirm a reply was delivered, or to 328 find out why one never arrived, without reading the channel's mirrored 329 conversation. 330 Outcomes cover **outbound agent messages only**. They carry no message 331 content, no author, and nothing about inbound messages. Access follows the 332 channel's binding the organization and app the channel is bound to and 333 needs no membership in the mirrored thread. 334 Paginated with opaque cursors, newest first. When `has_more` is true, pass the 335 response's `before_cursor` back as `before_cursor` to continue into older 336 history. `since` and `outcome` narrow the result set; they are filters, not 337 paging controls. 338 339 Args: 340 channel: Slack channel ID to read delivery outcomes for (e.g. `C01234ABCDE`). 341 since: Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age. 342 outcome: Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld. 343 limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200. 344 before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint. 345 after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row. 346 347 Returns: 348 Delivery outcomes for the requested channel, newest first. 349 """ 350 query: dict[str, object] = {} 351 if since is not None: 352 query["since"] = since 353 if outcome is not None: 354 query["outcome"] = outcome 355 if limit is not None: 356 query["limit"] = limit 357 if before_cursor is not None: 358 query["before_cursor"] = before_cursor 359 if after_cursor is not None: 360 query["after_cursor"] = after_cursor 361 return await self._http.request( 362 f"/api/v1/slack_channel_bindings/{channel}/delivery_outcomes", 363 query=query, 364 response_type=SlackDeliveryOutcomeListResponse, 365 )
List delivery outcomes for a Slack channel
Returns what happened to each agent message this platform sent to a Slack
channel, newest attempt first.
A message that never appears in a Slack channel has several possible causes
that look identical from the channel itself: a content guard withheld it, the
cross-org judge refused it, Slack rejected the call, or nobody asked anything.
This endpoint tells them apart. Use it to confirm a reply was delivered, or to
find out why one never arrived, without reading the channel's mirrored
conversation.
Outcomes cover outbound agent messages only. They carry no message
content, no author, and nothing about inbound messages. Access follows the
channel's binding the organization and app the channel is bound to and
needs no membership in the mirrored thread.
Paginated with opaque cursors, newest first. When has_more is true, pass the
response's before_cursor back as before_cursor to continue into older
history. since and outcome narrow the result set; they are filters, not
paging controls.
Arguments:
- channel: Slack channel ID to read delivery outcomes for (e.g.
C01234ABCDE). - since: Only return attempts at or after this ISO 8601 timestamp (e.g.
2026-08-11T00:00:00Z). Omit to return the most recent attempts regardless of age. - outcome: Return only attempts with this outcome. Omit to return every outcome. Use
flooredandjudge_refusedto see only what was withheld. - limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200.
- before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint.
- after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer
sincewith a little overlap and de-duplicate onidafter_cursorcan miss an attempt recorded in the same millisecond as the cursor's own row.
Returns:
Delivery outcomes for the requested channel, newest first.
367 async def deposit_thread( 368 self, channel: str, input: SlackChannelBindingDepositThreadInput 369 ) -> SlackChannelBinding: 370 """ 371 Point a Slack channel's deposit pipe at a staging thread, or turn it off 372 Sets the binding's deposit target the internal staging thread the 373 deposit pipe copies this channel's mirror content into. Pass a `null` 374 `thread_id` to turn the pipe off. 375 The target is validated server-side: it must exist, belong to the 376 binding's app and org, and never be a Slack mirror thread. Customer 377 bindings (bound `team_id`) additionally require a team-owned private 378 thread with no participant list, so the staging read ACL stays governed 379 by the channel-membership projection. Re-pointing or clearing an 380 existing target purges the old thread's deposit entries. 381 382 Args: 383 channel: Slack channel ID whose binding is being configured (e.g. `C01234ABCDE`). 384 input: Request body. 385 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 386 input.thread_id: Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off. 387 388 Returns: 389 The binding with the updated deposit config. 390 """ 391 return await self._http.request( 392 f"/api/v1/slack_channel_bindings/{channel}/deposit_thread", 393 method="POST", 394 body=input, 395 response_type=SlackChannelBinding, 396 )
Point a Slack channel's deposit pipe at a staging thread, or turn it off
Sets the binding's deposit target the internal staging thread the
deposit pipe copies this channel's mirror content into. Pass a null
thread_id to turn the pipe off.
The target is validated server-side: it must exist, belong to the
binding's app and org, and never be a Slack mirror thread. Customer
bindings (bound team_id) additionally require a team-owned private
thread with no participant list, so the staging read ACL stays governed
by the channel-membership projection. Re-pointing or clearing an
existing target purges the old thread's deposit entries.
Arguments:
- channel: Slack channel ID whose binding is being configured (e.g.
C01234ABCDE). - input: Request body.
- input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Identifies which Slack integration to use. - input.thread_id: Staging thread ID (primary key,
thr_) deposits should flow into. Passnullto turn the pipe off.
Returns:
The binding with the updated deposit config.
399class SlackChannelBindingResource: 400 def __init__(self, http: SyncHttpClient): 401 self._http = http 402 403 def list( 404 self, 405 *, 406 integration: builtins.list[str] | None = None, 407 team: builtins.list[str] | None = None, 408 agent: builtins.list[str] | None = None, 409 org: builtins.list[str] | None = None, 410 page: int | None = None, 411 per_page: int | None = None, 412 ) -> SlackChannelBindingListResponse: 413 """ 414 List Slack channel bindings 415 Returns a page of Slack channel bindings visible to the authenticated user. 416 Results can be filtered by integration, team, agent, or organization. Omit all 417 filter params to retrieve every binding the caller can see. 418 Pagination is page-based. Pass `page` and `per_page` to navigate large result 419 sets. `page` must be a positive integer; `per_page` must be between 1 and 100. 420 Invalid values return 400. 421 422 Args: 423 integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations. 424 team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams. 425 agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment. 426 org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller. 427 page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer. 428 per_page: Number of bindings to return per page. Defaults to 25; maximum is 100. 429 430 Returns: 431 Paginated list of Slack channel bindings visible to the caller. 432 """ 433 query: dict[str, object] = {} 434 if integration is not None: 435 query["integration"] = integration 436 if team is not None: 437 query["team"] = team 438 if agent is not None: 439 query["agent"] = agent 440 if org is not None: 441 query["org"] = org 442 if page is not None: 443 query["page"] = page 444 if per_page is not None: 445 query["per_page"] = per_page 446 return self._http.request( 447 "/api/v1/slack_channel_bindings", 448 query=query, 449 response_type=SlackChannelBindingListResponse, 450 ) 451 452 def create(self, input: SlackChannelBindingCreateInput) -> SlackChannelBinding: 453 """ 454 Create or update a Slack channel binding 455 Creates a new binding between a Slack channel and a team, or updates the 456 existing binding if one already exists for the given channel. The caller also 457 supplies a list of agents to attach to the binding and enroll as members of the 458 destination team. 459 The caller must have team-manage rights on the destination team (and on the 460 currently bound team if the channel is being re-pointed). Returns 403 if 461 permission is insufficient. All write steps are idempotent, so retrying after 462 a partial failure is safe. 463 On success the REST endpoint returns 201 Created. The script binding 464 (`slack.channel_bindings.upsert`) returns the full binding object including the 465 attached agents. 466 467 Args: 468 input: Request body. 469 input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents. 470 input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged. 471 input.channel_id: Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace. 472 input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted. 473 input.is_ext_shared_cached: Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted. 474 input.is_private_cached: Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted. 475 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 476 input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team. 477 478 Returns: 479 The created or updated Slack channel binding, including the full list of currently attached agents. 480 """ 481 return self._http.request( 482 "/api/v1/slack_channel_bindings", 483 method="POST", 484 body=input, 485 response_type=SlackChannelBinding, 486 ) 487 488 def assign(self, input: SlackChannelBindingAssignInput) -> SlackChannelBinding: 489 """ 490 Assign a Slack channel's resident agent 491 Makes the given agent the channel's sole resident (one resident per 492 channel: any previously attached agent is detached in the same 493 transaction and its mirror-thread read grant is revoked immediately). 494 Creates a bare internal binding first when the channel has none. 495 Fetches the channel's `is_private` / `is_ext_shared` flags live from 496 Slack (server-side, best-effort) to feed the fail-closed residency 497 gates: a channel shared with an external workspace but not yet bound to 498 a customer team fails with `team_required_for_shared_channel` (bind the 499 team first via `upsert`/setup), and a private channel is member-managed 500 mutation without platform-verified in-channel evidence fails with 501 `channel_membership_required`. 502 When the binding is bound to a customer team, the agent is also 503 enrolled as a member of that team (same pairing as `upsert`). 504 505 Args: 506 input: Request body. 507 input.agent_user_id: Agent user ID to assign as the channel's sole resident. 508 input.channel_id: Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none. 509 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 510 511 Returns: 512 The binding after assignment, with the attached agent list. 513 """ 514 return self._http.request( 515 "/api/v1/slack_channel_bindings/assign", 516 method="POST", 517 body=input, 518 response_type=SlackChannelBinding, 519 ) 520 521 def provision(self, input: SlackChannelBindingProvisionInput) -> SlackChannelBinding: 522 """ 523 Start adding a customer over Slack Connect 524 Opens a Slack Connect channel with a new customer creating one and sending 525 the invite, or adopting a shared channel you already have and records who is 526 adding whom so the addition can finish once the customer accepts. 527 The returned binding is **pending**: nothing mirrors, and no per-customer Team, 528 agent, or solution instance exists yet. Acceptance is asynchronous and may 529 never come. When it does, the addition completes in the background under the 530 identity of the admin who called this endpoint, re-checked live at that moment. 531 A caller who has since lost their admin role does not get a substitute the 532 addition is refused and a human re-adds the customer. 533 The caller must be an admin of the Slack integration's own organization. This 534 is the same authority the completion demands, checked here so a customer is 535 never invited into a channel whose addition can never finish. 536 Deliberately not exposed as a script binding: this sends mail to a person 537 outside the org, so it stays a vendor-admin HTTP surface. 538 539 Args: 540 input: Request body. 541 input.channel_name: Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private. 542 input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty. 543 input.customer_key: The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. 544 input.customer_label: Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. 545 input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`. 546 input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map. 547 input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts. 548 input.template_config_id: Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet. 549 550 Returns: 551 The pending binding for the customer's channel. `disclosure_state` is `pending` until the customer accepts, and `scope_key` is null until the addition finishes. 552 """ 553 return self._http.request( 554 "/api/v1/slack_channel_bindings/provision", 555 method="POST", 556 body=input, 557 response_type=SlackChannelBinding, 558 ) 559 560 def delete(self, channel: str) -> SlackChannelBindingDeleteResponse: 561 """ 562 Delete a Slack channel binding 563 Removes the binding between a Slack channel and its associated team. The 564 channel is identified by its Slack channel ID together with the `slack_team_id` 565 that scopes it to a specific Slack workspace. Removing the binding does not 566 delete the bound team or any conversation threads scoped to it; decommission 567 those resources separately if required. 568 The caller must have team-manage rights on the team the channel is currently 569 bound to. Returning 403 indicates insufficient permission; returning 404 570 indicates the binding does not exist or is not visible to the caller. 571 The REST endpoint returns 204 No Content on success. The script binding 572 (`slack.channel_bindings.delete`) returns a confirmation object so script 573 callers can verify success without an additional fetch. Both paths are 574 idempotent retrying after a partial failure is safe. 575 576 Args: 577 channel: Slack channel ID of the binding to delete (e.g. `C01234ABCDE`). 578 579 Returns: 580 Successful response 581 """ 582 return self._http.request( 583 f"/api/v1/slack_channel_bindings/{channel}", 584 method="DELETE", 585 response_type=SlackChannelBindingDeleteResponse, 586 ) 587 588 def get(self, channel: str, slack_team_id: str) -> SlackChannelBinding: 589 """ 590 Retrieve a Slack channel binding 591 Returns the Slack channel binding identified by a Slack channel ID and workspace 592 team ID pair. Use this endpoint to look up the team and agents currently bound 593 to a specific Slack channel. 594 The `channel` path parameter is the Slack channel ID; `slack_team_id` identifies 595 the Slack workspace the channel belongs to, disambiguating channels with the same 596 ID across workspaces. Both parameters are required. Returns 404 if no binding 597 exists for the given pair or the associated Slack integration is not visible to 598 the caller. 599 600 Args: 601 channel: Slack channel ID of the binding to retrieve (e.g. `C01234ABCDE`). 602 slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding. 603 604 Returns: 605 The Slack channel binding for the given channel and workspace. 606 """ 607 query: dict[str, object] = {} 608 query["slack_team_id"] = slack_team_id 609 return self._http.request( 610 f"/api/v1/slack_channel_bindings/{channel}", 611 query=query, 612 response_type=SlackChannelBinding, 613 ) 614 615 def delivery_outcomes( 616 self, 617 channel: str, 618 *, 619 since: str | None = None, 620 outcome: Literal["delivered", "floored", "judge_refused", "failed"] | None = None, 621 limit: int | None = None, 622 before_cursor: str | None = None, 623 after_cursor: str | None = None, 624 ) -> SlackDeliveryOutcomeListResponse: 625 """ 626 List delivery outcomes for a Slack channel 627 Returns what happened to each agent message this platform sent to a Slack 628 channel, newest attempt first. 629 A message that never appears in a Slack channel has several possible causes 630 that look identical from the channel itself: a content guard withheld it, the 631 cross-org judge refused it, Slack rejected the call, or nobody asked anything. 632 This endpoint tells them apart. Use it to confirm a reply was delivered, or to 633 find out why one never arrived, without reading the channel's mirrored 634 conversation. 635 Outcomes cover **outbound agent messages only**. They carry no message 636 content, no author, and nothing about inbound messages. Access follows the 637 channel's binding the organization and app the channel is bound to and 638 needs no membership in the mirrored thread. 639 Paginated with opaque cursors, newest first. When `has_more` is true, pass the 640 response's `before_cursor` back as `before_cursor` to continue into older 641 history. `since` and `outcome` narrow the result set; they are filters, not 642 paging controls. 643 644 Args: 645 channel: Slack channel ID to read delivery outcomes for (e.g. `C01234ABCDE`). 646 since: Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age. 647 outcome: Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld. 648 limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200. 649 before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint. 650 after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row. 651 652 Returns: 653 Delivery outcomes for the requested channel, newest first. 654 """ 655 query: dict[str, object] = {} 656 if since is not None: 657 query["since"] = since 658 if outcome is not None: 659 query["outcome"] = outcome 660 if limit is not None: 661 query["limit"] = limit 662 if before_cursor is not None: 663 query["before_cursor"] = before_cursor 664 if after_cursor is not None: 665 query["after_cursor"] = after_cursor 666 return self._http.request( 667 f"/api/v1/slack_channel_bindings/{channel}/delivery_outcomes", 668 query=query, 669 response_type=SlackDeliveryOutcomeListResponse, 670 ) 671 672 def deposit_thread( 673 self, channel: str, input: SlackChannelBindingDepositThreadInput 674 ) -> SlackChannelBinding: 675 """ 676 Point a Slack channel's deposit pipe at a staging thread, or turn it off 677 Sets the binding's deposit target the internal staging thread the 678 deposit pipe copies this channel's mirror content into. Pass a `null` 679 `thread_id` to turn the pipe off. 680 The target is validated server-side: it must exist, belong to the 681 binding's app and org, and never be a Slack mirror thread. Customer 682 bindings (bound `team_id`) additionally require a team-owned private 683 thread with no participant list, so the staging read ACL stays governed 684 by the channel-membership projection. Re-pointing or clearing an 685 existing target purges the old thread's deposit entries. 686 687 Args: 688 channel: Slack channel ID whose binding is being configured (e.g. `C01234ABCDE`). 689 input: Request body. 690 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 691 input.thread_id: Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off. 692 693 Returns: 694 The binding with the updated deposit config. 695 """ 696 return self._http.request( 697 f"/api/v1/slack_channel_bindings/{channel}/deposit_thread", 698 method="POST", 699 body=input, 700 response_type=SlackChannelBinding, 701 )
403 def list( 404 self, 405 *, 406 integration: builtins.list[str] | None = None, 407 team: builtins.list[str] | None = None, 408 agent: builtins.list[str] | None = None, 409 org: builtins.list[str] | None = None, 410 page: int | None = None, 411 per_page: int | None = None, 412 ) -> SlackChannelBindingListResponse: 413 """ 414 List Slack channel bindings 415 Returns a page of Slack channel bindings visible to the authenticated user. 416 Results can be filtered by integration, team, agent, or organization. Omit all 417 filter params to retrieve every binding the caller can see. 418 Pagination is page-based. Pass `page` and `per_page` to navigate large result 419 sets. `page` must be a positive integer; `per_page` must be between 1 and 100. 420 Invalid values return 400. 421 422 Args: 423 integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations. 424 team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams. 425 agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment. 426 org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller. 427 page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer. 428 per_page: Number of bindings to return per page. Defaults to 25; maximum is 100. 429 430 Returns: 431 Paginated list of Slack channel bindings visible to the caller. 432 """ 433 query: dict[str, object] = {} 434 if integration is not None: 435 query["integration"] = integration 436 if team is not None: 437 query["team"] = team 438 if agent is not None: 439 query["agent"] = agent 440 if org is not None: 441 query["org"] = org 442 if page is not None: 443 query["page"] = page 444 if per_page is not None: 445 query["per_page"] = per_page 446 return self._http.request( 447 "/api/v1/slack_channel_bindings", 448 query=query, 449 response_type=SlackChannelBindingListResponse, 450 )
List Slack channel bindings
Returns a page of Slack channel bindings visible to the authenticated user.
Results can be filtered by integration, team, agent, or organization. Omit all
filter params to retrieve every binding the caller can see.
Pagination is page-based. Pass page and per_page to navigate large result
sets. page must be a positive integer; per_page must be between 1 and 100.
Invalid values return 400.
Arguments:
- integration: Return only bindings whose Slack integration matches one of these integration IDs. Omit to return bindings across all integrations.
- team: Return only bindings bound to one of these team IDs. Omit to return bindings for all teams.
- agent: Return only bindings that have at least one of these agent user IDs attached. Omit to return bindings regardless of agent attachment.
- org: Return only bindings that belong to one of these organization IDs. Omit to return bindings across all organizations visible to the caller.
- page: Page number to retrieve, 1-indexed. Defaults to 1. Must be a positive integer.
- per_page: Number of bindings to return per page. Defaults to 25; maximum is 100.
Returns:
Paginated list of Slack channel bindings visible to the caller.
452 def create(self, input: SlackChannelBindingCreateInput) -> SlackChannelBinding: 453 """ 454 Create or update a Slack channel binding 455 Creates a new binding between a Slack channel and a team, or updates the 456 existing binding if one already exists for the given channel. The caller also 457 supplies a list of agents to attach to the binding and enroll as members of the 458 destination team. 459 The caller must have team-manage rights on the destination team (and on the 460 currently bound team if the channel is being re-pointed). Returns 403 if 461 permission is insufficient. All write steps are idempotent, so retrying after 462 a partial failure is safe. 463 On success the REST endpoint returns 201 Created. The script binding 464 (`slack.channel_bindings.upsert`) returns the full binding object including the 465 attached agents. 466 467 Args: 468 input: Request body. 469 input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents. 470 input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged. 471 input.channel_id: Slack channel ID to bind (e.g. `C01234ABCDE`). Acts as the natural key of the binding within the workspace. 472 input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config. `null` if omitted. 473 input.is_ext_shared_cached: Cached value of Slack's `is_ext_shared` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. `null` if omitted. 474 input.is_private_cached: Cached value of Slack's `is_private` flag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed. `null` if omitted. 475 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 476 input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team. 477 478 Returns: 479 The created or updated Slack channel binding, including the full list of currently attached agents. 480 """ 481 return self._http.request( 482 "/api/v1/slack_channel_bindings", 483 method="POST", 484 body=input, 485 response_type=SlackChannelBinding, 486 )
Create or update a Slack channel binding
Creates a new binding between a Slack channel and a team, or updates the
existing binding if one already exists for the given channel. The caller also
supplies a list of agents to attach to the binding and enroll as members of the
destination team.
The caller must have team-manage rights on the destination team (and on the
currently bound team if the channel is being re-pointed). Returns 403 if
permission is insufficient. All write steps are idempotent, so retrying after
a partial failure is safe.
On success the REST endpoint returns 201 Created. The script binding
(slack.channel_bindings.upsert) returns the full binding object including the
attached agents.
Arguments:
- input: Request body.
- input.agent_user_ids: List of agent user IDs to attach to the binding and enroll as members of the destination team. Pass an empty array to bind the channel without attaching any agents.
- input.allow_bot_conversations: Opt this channel into sustained bot-to-bot conversation: the reply loop brake is disabled for its mirror thread. Set when the counterparty is a known bot the agent should keep answering. Omitting the parameter leaves the stored value unchanged.
- input.channel_id: Slack channel ID to bind (e.g.
C01234ABCDE). Acts as the natural key of the binding within the workspace. - input.customer_label: Human-readable label for the customer associated with this channel. Stored in the binding's config.
nullif omitted. - input.is_ext_shared_cached: Cached value of Slack's
is_ext_sharedflag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups.nullif omitted. - input.is_private_cached: Cached value of Slack's
is_privateflag for the channel. When provided, this value is persisted on the binding to avoid repeated Slack API lookups. Private channels are member-managed.nullif omitted. - input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Identifies which Slack integration to use. - input.team_id: ID of the team to bind the Slack channel to. The caller must have team-manage rights on this team.
Returns:
The created or updated Slack channel binding, including the full list of currently attached agents.
488 def assign(self, input: SlackChannelBindingAssignInput) -> SlackChannelBinding: 489 """ 490 Assign a Slack channel's resident agent 491 Makes the given agent the channel's sole resident (one resident per 492 channel: any previously attached agent is detached in the same 493 transaction and its mirror-thread read grant is revoked immediately). 494 Creates a bare internal binding first when the channel has none. 495 Fetches the channel's `is_private` / `is_ext_shared` flags live from 496 Slack (server-side, best-effort) to feed the fail-closed residency 497 gates: a channel shared with an external workspace but not yet bound to 498 a customer team fails with `team_required_for_shared_channel` (bind the 499 team first via `upsert`/setup), and a private channel is member-managed 500 mutation without platform-verified in-channel evidence fails with 501 `channel_membership_required`. 502 When the binding is bound to a customer team, the agent is also 503 enrolled as a member of that team (same pairing as `upsert`). 504 505 Args: 506 input: Request body. 507 input.agent_user_id: Agent user ID to assign as the channel's sole resident. 508 input.channel_id: Slack channel ID whose resident is being assigned (e.g. `C01234ABCDE`). A bare internal binding is created when the channel has none. 509 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 510 511 Returns: 512 The binding after assignment, with the attached agent list. 513 """ 514 return self._http.request( 515 "/api/v1/slack_channel_bindings/assign", 516 method="POST", 517 body=input, 518 response_type=SlackChannelBinding, 519 )
Assign a Slack channel's resident agent
Makes the given agent the channel's sole resident (one resident per
channel: any previously attached agent is detached in the same
transaction and its mirror-thread read grant is revoked immediately).
Creates a bare internal binding first when the channel has none.
Fetches the channel's is_private / is_ext_shared flags live from
Slack (server-side, best-effort) to feed the fail-closed residency
gates: a channel shared with an external workspace but not yet bound to
a customer team fails with team_required_for_shared_channel (bind the
team first via upsert/setup), and a private channel is member-managed
mutation without platform-verified in-channel evidence fails with
channel_membership_required.
When the binding is bound to a customer team, the agent is also
enrolled as a member of that team (same pairing as upsert).
Arguments:
- input: Request body.
- input.agent_user_id: Agent user ID to assign as the channel's sole resident.
- input.channel_id: Slack channel ID whose resident is being assigned (e.g.
C01234ABCDE). A bare internal binding is created when the channel has none. - input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Identifies which Slack integration to use.
Returns:
The binding after assignment, with the attached agent list.
521 def provision(self, input: SlackChannelBindingProvisionInput) -> SlackChannelBinding: 522 """ 523 Start adding a customer over Slack Connect 524 Opens a Slack Connect channel with a new customer creating one and sending 525 the invite, or adopting a shared channel you already have and records who is 526 adding whom so the addition can finish once the customer accepts. 527 The returned binding is **pending**: nothing mirrors, and no per-customer Team, 528 agent, or solution instance exists yet. Acceptance is asynchronous and may 529 never come. When it does, the addition completes in the background under the 530 identity of the admin who called this endpoint, re-checked live at that moment. 531 A caller who has since lost their admin role does not get a substitute the 532 addition is refused and a human re-adds the customer. 533 The caller must be an admin of the Slack integration's own organization. This 534 is the same authority the completion demands, checked here so a customer is 535 never invited into a channel whose addition can never finish. 536 Deliberately not exposed as a script binding: this sends mail to a person 537 outside the org, so it stays a vendor-admin HTTP surface. 538 539 Args: 540 input: Request body. 541 input.channel_name: Name for a Slack channel to create for this customer. Required unless `existing_channel_id` is given. The channel is created private. 542 input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty. 543 input.customer_key: The vendor's own primary key for this customer (`customer_id` / `account_id` / `tenant_id`). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. 544 input.customer_label: Human-readable name for the customer (e.g. `Acme, Inc.`). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. 545 input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g. `C01234ABCDE`) instead of creating one. Mutually exclusive with `channel_name`. 546 input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map. 547 input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g. `T01234ABCDE`). The customer's workspace is not known yet it resolves from whoever accepts. 548 input.template_config_id: Config ID (`cfg_ `) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet. 549 550 Returns: 551 The pending binding for the customer's channel. `disclosure_state` is `pending` until the customer accepts, and `scope_key` is null until the addition finishes. 552 """ 553 return self._http.request( 554 "/api/v1/slack_channel_bindings/provision", 555 method="POST", 556 body=input, 557 response_type=SlackChannelBinding, 558 )
Start adding a customer over Slack Connect Opens a Slack Connect channel with a new customer creating one and sending the invite, or adopting a shared channel you already have and records who is adding whom so the addition can finish once the customer accepts. The returned binding is pending: nothing mirrors, and no per-customer Team, agent, or solution instance exists yet. Acceptance is asynchronous and may never come. When it does, the addition completes in the background under the identity of the admin who called this endpoint, re-checked live at that moment. A caller who has since lost their admin role does not get a substitute the addition is refused and a human re-adds the customer. The caller must be an admin of the Slack integration's own organization. This is the same authority the completion demands, checked here so a customer is never invited into a channel whose addition can never finish. Deliberately not exposed as a script binding: this sends mail to a person outside the org, so it stays a vendor-admin HTTP surface.
Arguments:
- input: Request body.
- input.channel_name: Name for a Slack channel to create for this customer. Required unless
existing_channel_idis given. The channel is created private. - input.customer_email: Address the Slack Connect invite is sent to. Required when creating a channel; optional when adopting one the customer is already in. Whoever accepts becomes the verified counterparty.
- input.customer_key: The vendor's own primary key for this customer (
customer_id/account_id/tenant_id). The per-customer agent's data access is locked to it. Immutable once the customer is added: re-targeting means offboarding and re-provisioning. - input.customer_label: Human-readable name for the customer (e.g.
Acme, Inc.). Used for the vendor's own dashboards and as the per-customer Team's name. Not an identity or an access control input. - input.existing_channel_id: Adopt this already-shared Slack Connect channel (e.g.
C01234ABCDE) instead of creating one. Mutually exclusive withchannel_name. - input.inputs: String-keyed values the per-customer solution instance is stamped with. Defaults to an empty map.
- input.slack_team_id: Slack workspace team ID of the vendor's own Slack installation (e.g.
T01234ABCDE). The customer's workspace is not known yet it resolves from whoever accepts. - input.template_config_id: Config ID (
cfg_) of the org-installed Solution the per-customer instance is stamped from. Must be the organization's own installed copy, not the catalog original instances stamped from a different config do not appear in the vendor's customer fleet.
Returns:
The pending binding for the customer's channel.
disclosure_stateispendinguntil the customer accepts, andscope_keyis null until the addition finishes.
560 def delete(self, channel: str) -> SlackChannelBindingDeleteResponse: 561 """ 562 Delete a Slack channel binding 563 Removes the binding between a Slack channel and its associated team. The 564 channel is identified by its Slack channel ID together with the `slack_team_id` 565 that scopes it to a specific Slack workspace. Removing the binding does not 566 delete the bound team or any conversation threads scoped to it; decommission 567 those resources separately if required. 568 The caller must have team-manage rights on the team the channel is currently 569 bound to. Returning 403 indicates insufficient permission; returning 404 570 indicates the binding does not exist or is not visible to the caller. 571 The REST endpoint returns 204 No Content on success. The script binding 572 (`slack.channel_bindings.delete`) returns a confirmation object so script 573 callers can verify success without an additional fetch. Both paths are 574 idempotent retrying after a partial failure is safe. 575 576 Args: 577 channel: Slack channel ID of the binding to delete (e.g. `C01234ABCDE`). 578 579 Returns: 580 Successful response 581 """ 582 return self._http.request( 583 f"/api/v1/slack_channel_bindings/{channel}", 584 method="DELETE", 585 response_type=SlackChannelBindingDeleteResponse, 586 )
Delete a Slack channel binding
Removes the binding between a Slack channel and its associated team. The
channel is identified by its Slack channel ID together with the slack_team_id
that scopes it to a specific Slack workspace. Removing the binding does not
delete the bound team or any conversation threads scoped to it; decommission
those resources separately if required.
The caller must have team-manage rights on the team the channel is currently
bound to. Returning 403 indicates insufficient permission; returning 404
indicates the binding does not exist or is not visible to the caller.
The REST endpoint returns 204 No Content on success. The script binding
(slack.channel_bindings.delete) returns a confirmation object so script
callers can verify success without an additional fetch. Both paths are
idempotent retrying after a partial failure is safe.
Arguments:
- channel: Slack channel ID of the binding to delete (e.g.
C01234ABCDE).
Returns:
Successful response
588 def get(self, channel: str, slack_team_id: str) -> SlackChannelBinding: 589 """ 590 Retrieve a Slack channel binding 591 Returns the Slack channel binding identified by a Slack channel ID and workspace 592 team ID pair. Use this endpoint to look up the team and agents currently bound 593 to a specific Slack channel. 594 The `channel` path parameter is the Slack channel ID; `slack_team_id` identifies 595 the Slack workspace the channel belongs to, disambiguating channels with the same 596 ID across workspaces. Both parameters are required. Returns 404 if no binding 597 exists for the given pair or the associated Slack integration is not visible to 598 the caller. 599 600 Args: 601 channel: Slack channel ID of the binding to retrieve (e.g. `C01234ABCDE`). 602 slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Used together with `channel` to uniquely identify the binding. 603 604 Returns: 605 The Slack channel binding for the given channel and workspace. 606 """ 607 query: dict[str, object] = {} 608 query["slack_team_id"] = slack_team_id 609 return self._http.request( 610 f"/api/v1/slack_channel_bindings/{channel}", 611 query=query, 612 response_type=SlackChannelBinding, 613 )
Retrieve a Slack channel binding
Returns the Slack channel binding identified by a Slack channel ID and workspace
team ID pair. Use this endpoint to look up the team and agents currently bound
to a specific Slack channel.
The channel path parameter is the Slack channel ID; slack_team_id identifies
the Slack workspace the channel belongs to, disambiguating channels with the same
ID across workspaces. Both parameters are required. Returns 404 if no binding
exists for the given pair or the associated Slack integration is not visible to
the caller.
Arguments:
- channel: Slack channel ID of the binding to retrieve (e.g.
C01234ABCDE). - slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Used together withchannelto uniquely identify the binding.
Returns:
The Slack channel binding for the given channel and workspace.
615 def delivery_outcomes( 616 self, 617 channel: str, 618 *, 619 since: str | None = None, 620 outcome: Literal["delivered", "floored", "judge_refused", "failed"] | None = None, 621 limit: int | None = None, 622 before_cursor: str | None = None, 623 after_cursor: str | None = None, 624 ) -> SlackDeliveryOutcomeListResponse: 625 """ 626 List delivery outcomes for a Slack channel 627 Returns what happened to each agent message this platform sent to a Slack 628 channel, newest attempt first. 629 A message that never appears in a Slack channel has several possible causes 630 that look identical from the channel itself: a content guard withheld it, the 631 cross-org judge refused it, Slack rejected the call, or nobody asked anything. 632 This endpoint tells them apart. Use it to confirm a reply was delivered, or to 633 find out why one never arrived, without reading the channel's mirrored 634 conversation. 635 Outcomes cover **outbound agent messages only**. They carry no message 636 content, no author, and nothing about inbound messages. Access follows the 637 channel's binding the organization and app the channel is bound to and 638 needs no membership in the mirrored thread. 639 Paginated with opaque cursors, newest first. When `has_more` is true, pass the 640 response's `before_cursor` back as `before_cursor` to continue into older 641 history. `since` and `outcome` narrow the result set; they are filters, not 642 paging controls. 643 644 Args: 645 channel: Slack channel ID to read delivery outcomes for (e.g. `C01234ABCDE`). 646 since: Only return attempts at or after this ISO 8601 timestamp (e.g. `2026-08-11T00:00:00Z`). Omit to return the most recent attempts regardless of age. 647 outcome: Return only attempts with this outcome. Omit to return every outcome. Use `floored` and `judge_refused` to see only what was withheld. 648 limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200. 649 before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint. 650 after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer `since` with a little overlap and de-duplicate on `id` `after_cursor` can miss an attempt recorded in the same millisecond as the cursor's own row. 651 652 Returns: 653 Delivery outcomes for the requested channel, newest first. 654 """ 655 query: dict[str, object] = {} 656 if since is not None: 657 query["since"] = since 658 if outcome is not None: 659 query["outcome"] = outcome 660 if limit is not None: 661 query["limit"] = limit 662 if before_cursor is not None: 663 query["before_cursor"] = before_cursor 664 if after_cursor is not None: 665 query["after_cursor"] = after_cursor 666 return self._http.request( 667 f"/api/v1/slack_channel_bindings/{channel}/delivery_outcomes", 668 query=query, 669 response_type=SlackDeliveryOutcomeListResponse, 670 )
List delivery outcomes for a Slack channel
Returns what happened to each agent message this platform sent to a Slack
channel, newest attempt first.
A message that never appears in a Slack channel has several possible causes
that look identical from the channel itself: a content guard withheld it, the
cross-org judge refused it, Slack rejected the call, or nobody asked anything.
This endpoint tells them apart. Use it to confirm a reply was delivered, or to
find out why one never arrived, without reading the channel's mirrored
conversation.
Outcomes cover outbound agent messages only. They carry no message
content, no author, and nothing about inbound messages. Access follows the
channel's binding the organization and app the channel is bound to and
needs no membership in the mirrored thread.
Paginated with opaque cursors, newest first. When has_more is true, pass the
response's before_cursor back as before_cursor to continue into older
history. since and outcome narrow the result set; they are filters, not
paging controls.
Arguments:
- channel: Slack channel ID to read delivery outcomes for (e.g.
C01234ABCDE). - since: Only return attempts at or after this ISO 8601 timestamp (e.g.
2026-08-11T00:00:00Z). Omit to return the most recent attempts regardless of age. - outcome: Return only attempts with this outcome. Omit to return every outcome. Use
flooredandjudge_refusedto see only what was withheld. - limit: Maximum number of outcomes to return. Defaults to 50; maximum is 200.
- before_cursor: Opaque cursor from a previous response; returns outcomes older than it. Cursors are not parseable and are only valid against this endpoint.
- after_cursor: Opaque cursor from a previous response; returns outcomes newer than it. Suited to a UI loading newer entries. To poll for everything recorded since a point in time, prefer
sincewith a little overlap and de-duplicate onidafter_cursorcan miss an attempt recorded in the same millisecond as the cursor's own row.
Returns:
Delivery outcomes for the requested channel, newest first.
672 def deposit_thread( 673 self, channel: str, input: SlackChannelBindingDepositThreadInput 674 ) -> SlackChannelBinding: 675 """ 676 Point a Slack channel's deposit pipe at a staging thread, or turn it off 677 Sets the binding's deposit target the internal staging thread the 678 deposit pipe copies this channel's mirror content into. Pass a `null` 679 `thread_id` to turn the pipe off. 680 The target is validated server-side: it must exist, belong to the 681 binding's app and org, and never be a Slack mirror thread. Customer 682 bindings (bound `team_id`) additionally require a team-owned private 683 thread with no participant list, so the staging read ACL stays governed 684 by the channel-membership projection. Re-pointing or clearing an 685 existing target purges the old thread's deposit entries. 686 687 Args: 688 channel: Slack channel ID whose binding is being configured (e.g. `C01234ABCDE`). 689 input: Request body. 690 input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g. `T01234ABCDE`). Identifies which Slack integration to use. 691 input.thread_id: Staging thread ID (primary key, `thr_ `) deposits should flow into. Pass `null` to turn the pipe off. 692 693 Returns: 694 The binding with the updated deposit config. 695 """ 696 return self._http.request( 697 f"/api/v1/slack_channel_bindings/{channel}/deposit_thread", 698 method="POST", 699 body=input, 700 response_type=SlackChannelBinding, 701 )
Point a Slack channel's deposit pipe at a staging thread, or turn it off
Sets the binding's deposit target the internal staging thread the
deposit pipe copies this channel's mirror content into. Pass a null
thread_id to turn the pipe off.
The target is validated server-side: it must exist, belong to the
binding's app and org, and never be a Slack mirror thread. Customer
bindings (bound team_id) additionally require a team-owned private
thread with no participant list, so the staging read ACL stays governed
by the channel-membership projection. Re-pointing or clearing an
existing target purges the old thread's deposit entries.
Arguments:
- channel: Slack channel ID whose binding is being configured (e.g.
C01234ABCDE). - input: Request body.
- input.slack_team_id: Slack workspace team ID that the channel belongs to (e.g.
T01234ABCDE). Identifies which Slack integration to use. - input.thread_id: Staging thread ID (primary key,
thr_) deposits should flow into. Passnullto turn the pipe off.
Returns:
The binding with the updated deposit config.