The shared Slack gateway is a Chickpea-operated service that holds the credentials of one shared, unlisted Slack app and routes that app’s events to your deployment. Where a customer-owned Slack app puts Slack and your deployment in direct contact, the gateway stands between them so nobody has to create or configure a Slack app. This page covers what the gateway sees, what it stores and for how long, how one delivery is admitted and recovered, and how to keep the gateway out of the path.
Only the Add to Slack lane loads the gateway. A deployment that chose Use your own Slack app never loads the gateway client.
How the gateway connects
On first use the deployment generates an ECDSA P-256 key pair, keeps the private key encrypted in its own credential keyring, and derives its deployment ID from a SHA-256 digest of the public key. The gateway binds one Slack workspace installation to that one deployment ID, and every request the deployment makes is signed with the private key.
Events do not arrive on an inbound URL. The deployment dials out and holds an authenticated session; the gateway offers events over that session. Outbound Slack calls travel the same way, as signed tenant-bound requests against a fixed allowlist of 33 Slack operations, from auth.test and chat.postMessage through usergroups.create and files.uploadV2. The deployment never receives a Slack token.
The gateway origin is set by CHICKPEA_GATEWAY_URL and defaults to the Chickpea-operated service. The value must be an HTTPS origin with no path, query, fragment, username, or password.
What it stores
| Held where | What | Retention |
|---|---|---|
| Gateway request handling | The Slack request body, in transient process memory while the signature is checked, the event is routed, and the receipt is awaited | Never written to Durable Object storage, KV, R2, logs, or analytics |
| Gateway installation state | Workspace, app, bot, installer, deployment, and binding identifiers, encrypted Slack installation tokens, granted scopes, health and session timestamps | Until the workspace disconnects or Slack revokes the installation, subject to operational backup retention |
| Gateway retry-notice suppression | Workspace and channel identifiers, plus Slack event_id. Content-free |
5 minutes and 25 hours respectively, then scheduled cleanup |
| Gateway delivery logs | Bounded reason codes and retry numbers, such as session_missing or receipt_timeout |
The operator’s log-retention policy |
| Your deployment’s inbox | The event envelope needed to process one delivery, in Durable Object state you operate | Scrubbed on completion, after the attempt limit, or when recovery is required |
| Your deployment’s deduplication record | Delivery, binding, and workspace IDs, event kind, status, attempt count, timestamps, and a bounded reason code | 48 hours after the row becomes terminal |
Three claims sit behind that table.
- The gateway does not durably store Slack message or event bodies. It verifies and routes them in memory. What it keeps is encrypted installation credentials and sanitized health metadata.
- Delivery logs carry no content. Message text, event envelopes, message-derived Slack fields, tool inputs and outputs, raw errors, and exception text are not part of them.
- The deduplication record is content-free. It holds identity and status for the delivery, not the delivery.
Chickpea’s transcript, memory, and run retention are separate features inside your deployment. The gateway receives no copy of that state.
How a delivery is admitted
On Cloudflare the shared lane trades a durable gateway queue for a live receipt.
- Slack sends an Events API request to the gateway.
- The gateway verifies Slack’s signature and offers the event to the authenticated session of the bound deployment.
- The deployment writes the delivery to its own durable inbox, then answers
acceptedorduplicate. Concurrent retries for the same delivery share one pending receipt. - Only then does the gateway acknowledge the request to Slack.
- The deployment drains the inbox, scrubs the payload the moment the delivery reaches a terminal state, and keeps the content-free deduplication row.
Durable admission is a capability the deployment advertises when it opens the session. The Cloudflare session declares durable_admission_v1.
Failure and recovery
If no deployment session is available, the receipt times out, or admission is rejected, the gateway returns a failure. It does not acknowledge and discard the event.
Slack then retries. By default Slack does not deliver events that are more than two hours late. With the shared app’s Delayed Events setting enabled, events stay eligible regardless of age and Slack follows its ordinary retries with hourly retries for 24 hours. Because the deployment deduplicates on Slack’s event identity, a late retry recovers a missed event without a second Agent run or a second reply.
Admission itself fails closed. When the protected deduplication bound is full, Chickpea rejects new admission rather than delete an unexpired record, so a retry can never be mistaken for a first delivery.
The deployment renews its outbound session before retiring the old one. If the successor fails before it is ready, the predecessor stays active. Admin reads live inbound-session health, and a stored healthy value is shown as Needs attention when the current session is offline or belongs to an older Worker version. On a late Slack retry, Chickpea may post one content-neutral offline notice, suppressed once per channel for 5 minutes and once per event for 25 hours.
Limits
| Limit | Value | Scope |
|---|---|---|
| Live delivery receipt | 2 seconds | Gateway waits for the deployment |
| Deduplication retention | 48 hours after the row becomes terminal | Deployment inbox |
| Protected deduplication rows | 1,000,000 | Deployment inbox |
| Active deliveries | 512 rows, 32 MiB | Deployment inbox |
| One delivery payload | 1 MiB | Deployment inbox and the session frame |
| Delivery attempts | 5, then recovery_required |
One delivery |
| Abandoned active delivery | Scrubbed after at most 7 days | Deployment inbox |
| Session heartbeat timeout | 90 seconds | Outbound session |
| Session rotation | At most 12 minutes | Outbound session |
A one-minute Cloudflare cron wakes the session Durable Object, so an evicted session comes back without an event to trigger it.
On Node
Node connects to the shared gateway, but its session advertises no durable-admission capability. The durable inbox and the 48-hour deduplication contract above are Cloudflare only, and the Node target does not promise durable admission to the gateway. Use your own Slack app for reliable Node ingress. A Node session that fails to start retries every 5 seconds.
Keeping the gateway out of the path
Choose Use your own Slack app on the private setup page. Slack then posts events straight to your deployment, which calls Slack with its own bot token, and the gateway and its installation state are absent from the path. That is the strongest infrastructure-isolation option, and it asks you to configure and operate the Slack app yourself. The lane is chosen once; moving to the other lane is a fresh deployment.
In either lane, model traffic and durable Agent state stay in the deployment and provider accounts you selected.
Why it works this way
The gateway exists so an operator can install Chickpea without creating a Slack app, which is the longest and most error-prone part of setup. Making it a credential and routing service rather than a queue keeps the privacy claim narrow enough to state in one sentence: it holds credentials and identifiers, not conversations. The cost of that choice is the live receipt. Because the gateway keeps no copy of an event, Slack has to be the retry source, and recovery depends on Slack’s retry policy rather than on Chickpea’s storage.
Fail-closed admission is the other half. A gateway that acknowledged an event it could not deliver would turn every deployment restart into silent data loss.
What is not covered
- This is a recovery window, not an exactly-once guarantee. Slack describes the Events API as best effort, and Slack owns the event while it waits to retry.
- Delayed Events is a Slack app setting, not a code path. Until it is enabled on the routed shared app and the acceptance canary passes live, the recovery window is Slack’s ordinary two hours.
- Slack interactivity requests are outside the window. They have different retry behaviour.
- The gateway is the part of the shared lane you do not operate. Self-hosted state is a Chickpea guarantee with two exceptions, and this is one of them.
- Node has no durable admission. The contract on this page is Cloudflare only.
Next steps
- The two Slack app lanes: how the two lanes differ and which to pick.
- Security model: the guarantees around this one, and the mechanism behind each.
- Get started on Cloudflare: deploy, then choose a lane on the setup page.
- Operate: running, watching, and upgrading a deployment on each target.
