GET /channels/{type}/{id}Getting a Channel
The Get Channel API fetches a single channel by its type and ID without creating it. It is the read-only counterpart to creating a channel: when the channel does not exist (or has been deleted), the API responds with 404 Not Found instead of creating it. This makes the same call work as an efficient existence check.
Before this endpoint, the only ways to fetch or check one known channel were a Query Channels call with a single-CID filter, which runs the full filter and sort query path, or watching/querying the channel, which creates it when it is missing. Get Channel uses a cache-first lookup, so it can skip the database entirely when the channel is already cached.
SDK support: dedicated SDK methods for this endpoint are rolling out. Until your SDK exposes one, call the REST endpoint directly (examples below) or use your SDK's low-level request helper.
When to use it
| You want to | Use |
|---|---|
| Fetch one channel whose type and ID you already know | Get Channel |
| Check whether a channel exists, without creating it | Get Channel (a 404 means it does not exist) |
| Fetch a channel, creating it when missing | Creating a channel (channel.create() / channel.query()) |
| Find channels by member set, filters, or sorting | Query Channels |
| Receive live events for a channel | Watch the channel (channel.watch()), which also creates it when missing |
Best practices
- Prefer Get Channel over a single-CID Query Channels call. Querying with
{ "cid": { "$eq": ... } }(or atype+idfilter) runs the full query machinery to return one known channel. Get Channel serves the same data from a cache-first path, which is cheaper for you (rate limits) and faster for your users. - Treat
404as a normal outcome, not an error. For existence checks (for example, checking for a buyer-to-seller conversation before offering a "start chat" button), a404is the expected negative answer. Do not log it as a failure or retry it. - Stay on the cheap path unless you need messages. By default the response contains the channel, its configuration, and its members. Only pass
state=truewhen you actually need messages, read state, or watchers hydrated. - Distinct channels are not covered. Channels created by member list get a generated ID, so their CID is not known up front. To find those, keep using Query Channels with a
membersfilter, or create-or-get them withchannel.create().
Making the request
Request options are passed JSON-encoded in the payload query parameter, like other Stream GET endpoints. The payload parameter is required: pass {} for the defaults.
Fetching a channel (cheap default path):
curl -G "https://chat.stream-io-api.com/channels/${CHANNEL_TYPE}/${CHANNEL_ID}" \
--data-urlencode "api_key=${API_KEY}" \
--data-urlencode 'payload={}' \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt"Existence check (create only when missing):
status=$(curl -sG -o /dev/null -w "%{http_code}" \
"https://chat.stream-io-api.com/channels/${CHANNEL_TYPE}/${CHANNEL_ID}" \
--data-urlencode "api_key=${API_KEY}" \
--data-urlencode 'payload={}' \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt")
if [ "$status" = "404" ]; then
# channel does not exist; create it (or skip, depending on your flow)
echo "channel is missing"
fiFetching full channel state (messages, read state, watchers):
curl -G "https://chat.stream-io-api.com/channels/${CHANNEL_TYPE}/${CHANNEL_ID}" \
--data-urlencode "api_key=${API_KEY}" \
--data-urlencode 'payload={"state": true, "messages_limit": 25, "watchers_limit": 10}' \
-H "Authorization: ${TOKEN}" \
-H "stream-auth-type: jwt"The endpoint works with both authentication modes:
- Server-side (API secret signed token): no user is required. Add
"user_id": "<id>"to the payload to resolve membership and capabilities for a specific user. - Client-side (user token): the calling user needs the
ReadChannelpermission on the channel, typically granted through membership.
Request options
All options are optional.
| Option | Type | Default | Description |
|---|---|---|---|
state | boolean | false | When true, also hydrate messages, read state, watchers, and threads, like a channel query. When false, return only the channel, its config, and its members. |
messages_limit | integer | 100 | Maximum number of messages to return. Applies only when state is true. |
members_limit | integer | 100 | Maximum number of members to return. Applies only when state is true; the default path returns the channel's cached members without truncation. |
watchers_limit | integer | 0 | Maximum number of watchers to return. Watchers are omitted unless this is set to a positive value together with state=true. |
Response
The response has the same shape as a channel query response (channel, members, membership, messages, read, watchers, ...), so existing deserialization code can be reused. With state=false the messages, read, and watchers arrays are empty.
Because the endpoint performs no writes, it emits no events and does not affect unread counts, watchers, or presence.
Errors
| Status | Condition |
|---|---|
400 | The payload query parameter is missing or not valid JSON. |
403 | The user lacks the ReadChannel permission, or the channel is disabled (client-side requests). |
404 | The channel does not exist or has been deleted. |
Rate limits
Get Channel shares the same high rate limit tier as Query Channels, so replacing single-CID Query Channels calls with Get Channel never lowers your available request budget.